Roll ANGLE e754fb8..6ffeb74
[chromium-blink-merge.git] / content / browser / site_per_process_browsertest.cc
blob9e266bf5b2b9abcf60a2e9622913978341aa4aba
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/stringprintf.h"
14 #include "base/strings/utf_string_conversions.h"
15 #include "base/thread_task_runner_handle.h"
16 #include "content/browser/frame_host/cross_process_frame_connector.h"
17 #include "content/browser/frame_host/frame_tree.h"
18 #include "content/browser/frame_host/navigator.h"
19 #include "content/browser/frame_host/render_frame_proxy_host.h"
20 #include "content/browser/frame_host/render_widget_host_view_child_frame.h"
21 #include "content/browser/renderer_host/render_view_host_impl.h"
22 #include "content/browser/web_contents/web_contents_impl.h"
23 #include "content/common/frame_messages.h"
24 #include "content/public/browser/notification_observer.h"
25 #include "content/public/browser/notification_service.h"
26 #include "content/public/browser/notification_types.h"
27 #include "content/public/common/content_switches.h"
28 #include "content/public/test/browser_test_utils.h"
29 #include "content/public/test/content_browser_test_utils.h"
30 #include "content/public/test/test_navigation_observer.h"
31 #include "content/public/test/test_utils.h"
32 #include "content/shell/browser/shell.h"
33 #include "content/test/content_browser_test_utils_internal.h"
34 #include "content/test/test_frame_navigation_observer.h"
35 #include "ipc/ipc_security_test_util.h"
36 #include "net/dns/mock_host_resolver.h"
37 #include "net/test/embedded_test_server/embedded_test_server.h"
38 #include "third_party/WebKit/public/web/WebSandboxFlags.h"
40 namespace content {
42 namespace {
44 // Helper function to send a postMessage and wait for a reply message. The
45 // |post_message_script| is executed on the |sender_ftn| frame, and the sender
46 // frame is expected to post |reply_status| from the DOMAutomationController
47 // when it receives a reply.
48 void PostMessageAndWaitForReply(FrameTreeNode* sender_ftn,
49 const std::string& post_message_script,
50 const std::string& reply_status) {
51 bool success = false;
52 EXPECT_TRUE(ExecuteScriptAndExtractBool(
53 sender_ftn->current_frame_host(),
54 "window.domAutomationController.send(" + post_message_script + ");",
55 &success));
56 EXPECT_TRUE(success);
58 content::DOMMessageQueue msg_queue;
59 std::string status;
60 while (msg_queue.WaitForMessage(&status)) {
61 if (status == reply_status)
62 break;
66 class RedirectNotificationObserver : public NotificationObserver {
67 public:
68 // Register to listen for notifications of the given type from either a
69 // specific source, or from all sources if |source| is
70 // NotificationService::AllSources().
71 RedirectNotificationObserver(int notification_type,
72 const NotificationSource& source);
73 ~RedirectNotificationObserver() override;
75 // Wait until the specified notification occurs. If the notification was
76 // emitted between the construction of this object and this call then it
77 // returns immediately.
78 void Wait();
80 // Returns NotificationService::AllSources() if we haven't observed a
81 // notification yet.
82 const NotificationSource& source() const {
83 return source_;
86 const NotificationDetails& details() const {
87 return details_;
90 // NotificationObserver:
91 void Observe(int type,
92 const NotificationSource& source,
93 const NotificationDetails& details) override;
95 private:
96 bool seen_;
97 bool seen_twice_;
98 bool running_;
99 NotificationRegistrar registrar_;
101 NotificationSource source_;
102 NotificationDetails details_;
103 scoped_refptr<MessageLoopRunner> message_loop_runner_;
105 DISALLOW_COPY_AND_ASSIGN(RedirectNotificationObserver);
108 RedirectNotificationObserver::RedirectNotificationObserver(
109 int notification_type,
110 const NotificationSource& source)
111 : seen_(false),
112 running_(false),
113 source_(NotificationService::AllSources()) {
114 registrar_.Add(this, notification_type, source);
117 RedirectNotificationObserver::~RedirectNotificationObserver() {}
119 void RedirectNotificationObserver::Wait() {
120 if (seen_ && seen_twice_)
121 return;
123 running_ = true;
124 message_loop_runner_ = new MessageLoopRunner;
125 message_loop_runner_->Run();
126 EXPECT_TRUE(seen_);
129 void RedirectNotificationObserver::Observe(
130 int type,
131 const NotificationSource& source,
132 const NotificationDetails& details) {
133 source_ = source;
134 details_ = details;
135 seen_twice_ = seen_;
136 seen_ = true;
137 if (!running_)
138 return;
140 message_loop_runner_->Quit();
141 running_ = false;
144 // This observer keeps track of the number of created RenderFrameHosts. Tests
145 // can use this to ensure that a certain number of child frames has been
146 // created after navigating.
147 class RenderFrameHostCreatedObserver : public WebContentsObserver {
148 public:
149 RenderFrameHostCreatedObserver(WebContents* web_contents,
150 int expected_frame_count)
151 : WebContentsObserver(web_contents),
152 expected_frame_count_(expected_frame_count),
153 frames_created_(0),
154 message_loop_runner_(new MessageLoopRunner) {}
156 ~RenderFrameHostCreatedObserver() override;
158 // Runs a nested message loop and blocks until the expected number of
159 // RenderFrameHosts is created.
160 void Wait();
162 private:
163 // WebContentsObserver
164 void RenderFrameCreated(RenderFrameHost* render_frame_host) override;
166 // The number of RenderFrameHosts to wait for.
167 int expected_frame_count_;
169 // The number of RenderFrameHosts that have been created.
170 int frames_created_;
172 // The MessageLoopRunner used to spin the message loop.
173 scoped_refptr<MessageLoopRunner> message_loop_runner_;
175 DISALLOW_COPY_AND_ASSIGN(RenderFrameHostCreatedObserver);
178 RenderFrameHostCreatedObserver::~RenderFrameHostCreatedObserver() {
181 void RenderFrameHostCreatedObserver::Wait() {
182 message_loop_runner_->Run();
185 void RenderFrameHostCreatedObserver::RenderFrameCreated(
186 RenderFrameHost* render_frame_host) {
187 frames_created_++;
188 if (frames_created_ == expected_frame_count_) {
189 message_loop_runner_->Quit();
193 // A WebContentsDelegate that catches messages sent to the console.
194 class ConsoleObserverDelegate : public WebContentsDelegate {
195 public:
196 ConsoleObserverDelegate(WebContents* web_contents, const std::string& filter)
197 : web_contents_(web_contents),
198 filter_(filter),
199 message_(""),
200 message_loop_runner_(new MessageLoopRunner) {}
202 ~ConsoleObserverDelegate() override {}
204 bool AddMessageToConsole(WebContents* source,
205 int32 level,
206 const base::string16& message,
207 int32 line_no,
208 const base::string16& source_id) override;
210 std::string message() { return message_; }
212 void Wait();
214 private:
215 WebContents* web_contents_;
216 std::string filter_;
217 std::string message_;
219 // The MessageLoopRunner used to spin the message loop.
220 scoped_refptr<MessageLoopRunner> message_loop_runner_;
222 DISALLOW_COPY_AND_ASSIGN(ConsoleObserverDelegate);
225 void ConsoleObserverDelegate::Wait() {
226 message_loop_runner_->Run();
229 bool ConsoleObserverDelegate::AddMessageToConsole(
230 WebContents* source,
231 int32 level,
232 const base::string16& message,
233 int32 line_no,
234 const base::string16& source_id) {
235 DCHECK(source == web_contents_);
237 std::string ascii_message = base::UTF16ToASCII(message);
238 if (MatchPattern(ascii_message, filter_)) {
239 message_ = ascii_message;
240 message_loop_runner_->Quit();
242 return false;
245 } // namespace
248 // SitePerProcessBrowserTest
251 SitePerProcessBrowserTest::SitePerProcessBrowserTest() {
254 std::string SitePerProcessBrowserTest::DepictFrameTree(FrameTreeNode* node) {
255 return visualizer_.DepictFrameTree(node);
258 void SitePerProcessBrowserTest::StartFrameAtDataURL() {
259 std::string data_url_script =
260 "var iframes = document.getElementById('test');iframes.src="
261 "'data:text/html,dataurl';";
262 ASSERT_TRUE(ExecuteScript(shell()->web_contents(), data_url_script));
265 void SitePerProcessBrowserTest::SetUpCommandLine(
266 base::CommandLine* command_line) {
267 command_line->AppendSwitch(switches::kSitePerProcess);
270 void SitePerProcessBrowserTest::SetUpOnMainThread() {
271 host_resolver()->AddRule("*", "127.0.0.1");
272 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
273 SetupCrossSiteRedirector(embedded_test_server());
276 // Ensure that navigating subframes in --site-per-process mode works and the
277 // correct documents are committed.
278 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframe) {
279 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
280 NavigateToURL(shell(), main_url);
282 // It is safe to obtain the root frame tree node here, as it doesn't change.
283 FrameTreeNode* root =
284 static_cast<WebContentsImpl*>(shell()->web_contents())->
285 GetFrameTree()->root();
287 TestNavigationObserver observer(shell()->web_contents());
289 // Load same-site page into iframe.
290 FrameTreeNode* child = root->child_at(0);
291 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
292 NavigateFrameToURL(child, http_url);
293 EXPECT_EQ(http_url, observer.last_navigation_url());
294 EXPECT_TRUE(observer.last_navigation_succeeded());
296 // There should be only one RenderWidgetHost when there are no
297 // cross-process iframes.
298 std::set<RenderWidgetHostView*> views_set =
299 static_cast<WebContentsImpl*>(shell()->web_contents())
300 ->GetRenderWidgetHostViewsInTree();
301 EXPECT_EQ(1U, views_set.size());
304 EXPECT_EQ(
305 " Site A\n"
306 " |--Site A\n"
307 " +--Site A\n"
308 " |--Site A\n"
309 " +--Site A\n"
310 " +--Site A\n"
311 "Where A = http://127.0.0.1/",
312 DepictFrameTree(root));
314 // Load cross-site page into iframe.
315 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
316 NavigateFrameToURL(root->child_at(0), url);
317 // Verify that the navigation succeeded and the expected URL was loaded.
318 EXPECT_TRUE(observer.last_navigation_succeeded());
319 EXPECT_EQ(url, observer.last_navigation_url());
321 // Ensure that we have created a new process for the subframe.
322 ASSERT_EQ(2U, root->child_count());
323 SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
324 RenderViewHost* rvh = child->current_frame_host()->render_view_host();
325 RenderProcessHost* rph = child->current_frame_host()->GetProcess();
326 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh);
327 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
328 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), rph);
330 // There should be now two RenderWidgetHosts, one for each process
331 // rendering a frame.
332 std::set<RenderWidgetHostView*> views_set =
333 static_cast<WebContentsImpl*>(shell()->web_contents())
334 ->GetRenderWidgetHostViewsInTree();
335 EXPECT_EQ(2U, views_set.size());
337 RenderFrameProxyHost* proxy_to_parent =
338 child->render_manager()->GetProxyToParent();
339 EXPECT_TRUE(proxy_to_parent);
340 EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
341 // The out-of-process iframe should have its own RenderWidgetHost,
342 // independent of any RenderViewHost.
343 EXPECT_NE(
344 rvh->GetView(),
345 proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
346 EXPECT_TRUE(child->current_frame_host()->GetRenderWidgetHost());
348 EXPECT_EQ(
349 " Site A ------------ proxies for B\n"
350 " |--Site B ------- proxies for A\n"
351 " +--Site A ------- proxies for B\n"
352 " |--Site A -- proxies for B\n"
353 " +--Site A -- proxies for B\n"
354 " +--Site A -- proxies for B\n"
355 "Where A = http://127.0.0.1/\n"
356 " B = http://foo.com/",
357 DepictFrameTree(root));
359 // Load another cross-site page into the same iframe.
360 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
361 NavigateFrameToURL(root->child_at(0), url);
362 EXPECT_TRUE(observer.last_navigation_succeeded());
363 EXPECT_EQ(url, observer.last_navigation_url());
365 // Check again that a new process is created and is different from the
366 // top level one and the previous one.
367 ASSERT_EQ(2U, root->child_count());
368 child = root->child_at(0);
369 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(),
370 child->current_frame_host()->render_view_host());
371 EXPECT_NE(rvh, child->current_frame_host()->render_view_host());
372 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
373 child->current_frame_host()->GetSiteInstance());
374 EXPECT_NE(site_instance,
375 child->current_frame_host()->GetSiteInstance());
376 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(),
377 child->current_frame_host()->GetProcess());
378 EXPECT_NE(rph, child->current_frame_host()->GetProcess());
380 std::set<RenderWidgetHostView*> views_set =
381 static_cast<WebContentsImpl*>(shell()->web_contents())
382 ->GetRenderWidgetHostViewsInTree();
383 EXPECT_EQ(2U, views_set.size());
385 EXPECT_EQ(proxy_to_parent, child->render_manager()->GetProxyToParent());
386 EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
387 EXPECT_NE(
388 child->current_frame_host()->render_view_host()->GetView(),
389 proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
390 EXPECT_TRUE(child->current_frame_host()->GetRenderWidgetHost());
392 EXPECT_EQ(
393 " Site A ------------ proxies for C\n"
394 " |--Site C ------- proxies for A\n"
395 " +--Site A ------- proxies for C\n"
396 " |--Site A -- proxies for C\n"
397 " +--Site A -- proxies for C\n"
398 " +--Site A -- proxies for C\n"
399 "Where A = http://127.0.0.1/\n"
400 " C = http://bar.com/",
401 DepictFrameTree(root));
404 // Tests OOPIF rendering by checking that the RWH of the iframe generates
405 // OnSwapCompositorFrame message.
406 #if defined(OS_ANDROID)
407 // http://crbug.com/471850
408 #define MAYBE_CompositorFrameSwapped DISABLED_CompositorFrameSwapped
409 #else
410 #define MAYBE_CompositorFrameSwapped CompositorFrameSwapped
411 #endif
412 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
413 MAYBE_CompositorFrameSwapped) {
414 GURL main_url(
415 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
416 NavigateToURL(shell(), main_url);
418 // It is safe to obtain the root frame tree node here, as it doesn't change.
419 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
420 ->GetFrameTree()
421 ->root();
422 ASSERT_EQ(1U, root->child_count());
424 FrameTreeNode* child_node = root->child_at(0);
425 GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
426 EXPECT_EQ(site_url, child_node->current_url());
427 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
428 child_node->current_frame_host()->GetSiteInstance());
429 RenderWidgetHostViewBase* rwhv_base = static_cast<RenderWidgetHostViewBase*>(
430 child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
432 // Wait for OnSwapCompositorFrame message.
433 while (rwhv_base->RendererFrameNumber() <= 0) {
434 // TODO(lazyboy): Find a better way to avoid sleeping like this. See
435 // http://crbug.com/405282 for details.
436 base::RunLoop run_loop;
437 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
438 FROM_HERE, run_loop.QuitClosure(),
439 base::TimeDelta::FromMilliseconds(10));
440 run_loop.Run();
444 // Ensure that OOPIFs are deleted after navigating to a new main frame.
445 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CleanupCrossSiteIframe) {
446 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
447 NavigateToURL(shell(), main_url);
449 // It is safe to obtain the root frame tree node here, as it doesn't change.
450 FrameTreeNode* root =
451 static_cast<WebContentsImpl*>(shell()->web_contents())->
452 GetFrameTree()->root();
454 TestNavigationObserver observer(shell()->web_contents());
456 // Load a cross-site page into both iframes.
457 GURL foo_url = embedded_test_server()->GetURL("foo.com", "/title2.html");
458 NavigateFrameToURL(root->child_at(0), foo_url);
459 EXPECT_TRUE(observer.last_navigation_succeeded());
460 EXPECT_EQ(foo_url, observer.last_navigation_url());
461 NavigateFrameToURL(root->child_at(1), foo_url);
462 EXPECT_TRUE(observer.last_navigation_succeeded());
463 EXPECT_EQ(foo_url, observer.last_navigation_url());
465 // Ensure that we have created a new process for the subframes.
466 EXPECT_EQ(
467 " Site A ------------ proxies for B\n"
468 " |--Site B ------- proxies for A\n"
469 " +--Site B ------- proxies for A\n"
470 "Where A = http://127.0.0.1/\n"
471 " B = http://foo.com/",
472 DepictFrameTree(root));
474 int subframe_process_id = root->child_at(0)
475 ->current_frame_host()
476 ->GetSiteInstance()
477 ->GetProcess()
478 ->GetID();
479 int subframe_rvh_id = root->child_at(0)
480 ->current_frame_host()
481 ->render_view_host()
482 ->GetRoutingID();
483 EXPECT_TRUE(RenderViewHost::FromID(subframe_process_id, subframe_rvh_id));
485 // Use Javascript in the parent to remove one of the frames and ensure that
486 // the subframe goes away.
487 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
488 "document.body.removeChild("
489 "document.querySelectorAll('iframe')[0])"));
490 ASSERT_EQ(1U, root->child_count());
492 // Load a new same-site page in the top-level frame and ensure the other
493 // subframe goes away.
494 GURL new_url(embedded_test_server()->GetURL("/title1.html"));
495 NavigateToURL(shell(), new_url);
496 ASSERT_EQ(0U, root->child_count());
498 // Ensure the RVH for the subframe gets cleaned up when the frame goes away.
499 EXPECT_FALSE(RenderViewHost::FromID(subframe_process_id, subframe_rvh_id));
502 // Ensure that root frames cannot be detached.
503 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, RestrictFrameDetach) {
504 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
505 NavigateToURL(shell(), main_url);
507 // It is safe to obtain the root frame tree node here, as it doesn't change.
508 FrameTreeNode* root =
509 static_cast<WebContentsImpl*>(shell()->web_contents())->
510 GetFrameTree()->root();
512 TestNavigationObserver observer(shell()->web_contents());
514 // Load cross-site pages into both iframes.
515 GURL foo_url = embedded_test_server()->GetURL("foo.com", "/title2.html");
516 NavigateFrameToURL(root->child_at(0), foo_url);
517 EXPECT_TRUE(observer.last_navigation_succeeded());
518 EXPECT_EQ(foo_url, observer.last_navigation_url());
519 GURL bar_url = embedded_test_server()->GetURL("bar.com", "/title2.html");
520 NavigateFrameToURL(root->child_at(1), bar_url);
521 EXPECT_TRUE(observer.last_navigation_succeeded());
522 EXPECT_EQ(bar_url, observer.last_navigation_url());
524 // Ensure that we have created new processes for the subframes.
525 ASSERT_EQ(2U, root->child_count());
526 FrameTreeNode* foo_child = root->child_at(0);
527 SiteInstance* foo_site_instance =
528 foo_child->current_frame_host()->GetSiteInstance();
529 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), foo_site_instance);
530 FrameTreeNode* bar_child = root->child_at(1);
531 SiteInstance* bar_site_instance =
532 bar_child->current_frame_host()->GetSiteInstance();
533 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), bar_site_instance);
535 EXPECT_EQ(
536 " Site A ------------ proxies for B C\n"
537 " |--Site B ------- proxies for A C\n"
538 " +--Site C ------- proxies for A B\n"
539 "Where A = http://127.0.0.1/\n"
540 " B = http://foo.com/\n"
541 " C = http://bar.com/",
542 DepictFrameTree(root));
544 // Simulate an attempt to detach the root frame from foo_site_instance. This
545 // should kill foo_site_instance's process.
546 RenderFrameProxyHost* foo_mainframe_rfph =
547 root->render_manager()->GetRenderFrameProxyHost(foo_site_instance);
548 content::RenderProcessHostWatcher foo_terminated(
549 foo_mainframe_rfph->GetProcess(),
550 content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
551 FrameHostMsg_Detach evil_msg2(foo_mainframe_rfph->GetRoutingID());
552 IPC::IpcSecurityTestUtil::PwnMessageReceived(
553 foo_mainframe_rfph->GetProcess()->GetChannel(), evil_msg2);
554 foo_terminated.Wait();
556 EXPECT_EQ(
557 " Site A ------------ proxies for B C\n"
558 " |--Site B ------- proxies for A C\n"
559 " +--Site C ------- proxies for A B\n"
560 "Where A = http://127.0.0.1/\n"
561 " B = http://foo.com/ (no process)\n"
562 " C = http://bar.com/",
563 DepictFrameTree(root));
566 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
567 NavigateRemoteFrame) {
568 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
569 NavigateToURL(shell(), main_url);
571 // It is safe to obtain the root frame tree node here, as it doesn't change.
572 FrameTreeNode* root =
573 static_cast<WebContentsImpl*>(shell()->web_contents())->
574 GetFrameTree()->root();
576 TestNavigationObserver observer(shell()->web_contents());
578 // Load same-site page into iframe.
579 FrameTreeNode* child = root->child_at(0);
580 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
581 NavigateFrameToURL(child, http_url);
582 EXPECT_EQ(http_url, observer.last_navigation_url());
583 EXPECT_TRUE(observer.last_navigation_succeeded());
585 // Load cross-site page into iframe.
586 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
587 NavigateFrameToURL(root->child_at(0), url);
588 EXPECT_TRUE(observer.last_navigation_succeeded());
589 EXPECT_EQ(url, observer.last_navigation_url());
591 // Ensure that we have created a new process for the subframe.
592 ASSERT_EQ(2U, root->child_count());
593 SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
594 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
596 // Emulate the main frame changing the src of the iframe such that it
597 // navigates cross-site.
598 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
599 NavigateIframeToURL(shell()->web_contents(), "test", url);
600 EXPECT_TRUE(observer.last_navigation_succeeded());
601 EXPECT_EQ(url, observer.last_navigation_url());
603 // Check again that a new process is created and is different from the
604 // top level one and the previous one.
605 ASSERT_EQ(2U, root->child_count());
606 child = root->child_at(0);
607 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
608 child->current_frame_host()->GetSiteInstance());
609 EXPECT_NE(site_instance,
610 child->current_frame_host()->GetSiteInstance());
612 // Navigate back to the parent's origin and ensure we return to the
613 // parent's process.
614 NavigateFrameToURL(child, http_url);
615 EXPECT_EQ(http_url, observer.last_navigation_url());
616 EXPECT_TRUE(observer.last_navigation_succeeded());
617 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
618 child->current_frame_host()->GetSiteInstance());
621 #if defined(OS_WIN)
622 // http://crbug.com/465722
623 #define MAYBE_NavigateRemoteFrameToBlankAndDataURLs \
624 DISABLED_NavigateRemoteFrameToBlankAndDataURLs
625 #else
626 #define MAYBE_NavigateRemoteFrameToBlankAndDataURLs \
627 NavigateRemoteFrameToBlankAndDataURLs
628 #endif
630 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
631 MAYBE_NavigateRemoteFrameToBlankAndDataURLs) {
632 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
633 NavigateToURL(shell(), main_url);
635 // It is safe to obtain the root frame tree node here, as it doesn't change.
636 FrameTreeNode* root =
637 static_cast<WebContentsImpl*>(shell()->web_contents())->
638 GetFrameTree()->root();
640 TestNavigationObserver observer(shell()->web_contents());
642 // Load same-site page into iframe.
643 FrameTreeNode* child = root->child_at(0);
644 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
645 NavigateFrameToURL(child, http_url);
646 EXPECT_EQ(http_url, observer.last_navigation_url());
647 EXPECT_TRUE(observer.last_navigation_succeeded());
649 // Load cross-site page into iframe.
650 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
651 NavigateFrameToURL(root->child_at(0), url);
652 EXPECT_TRUE(observer.last_navigation_succeeded());
653 EXPECT_EQ(url, observer.last_navigation_url());
654 ASSERT_EQ(2U, root->child_count());
655 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
656 root->child_at(0)->current_frame_host()->GetSiteInstance());
658 // Navigate iframe to a data URL. The navigation happens from a script in the
659 // parent frame, so the data URL should be committed in the same SiteInstance
660 // as the parent frame.
661 GURL data_url("data:text/html,dataurl");
662 NavigateIframeToURL(shell()->web_contents(), "test", data_url);
663 EXPECT_TRUE(observer.last_navigation_succeeded());
664 EXPECT_EQ(data_url, observer.last_navigation_url());
666 // Ensure that we have navigated using the top level process.
667 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
668 root->child_at(0)->current_frame_host()->GetSiteInstance());
670 // Load cross-site page into iframe.
671 url = embedded_test_server()->GetURL("bar.com", "/title2.html");
672 NavigateFrameToURL(root->child_at(0), url);
673 EXPECT_TRUE(observer.last_navigation_succeeded());
674 EXPECT_EQ(url, observer.last_navigation_url());
675 ASSERT_EQ(2U, root->child_count());
676 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
677 root->child_at(0)->current_frame_host()->GetSiteInstance());
679 // Navigate iframe to about:blank. The navigation happens from a script in the
680 // parent frame, so it should be committed in the same SiteInstance as the
681 // parent frame.
682 GURL about_blank_url("about:blank");
683 NavigateIframeToURL(shell()->web_contents(), "test", about_blank_url);
684 EXPECT_TRUE(observer.last_navigation_succeeded());
685 EXPECT_EQ(about_blank_url, observer.last_navigation_url());
687 // Ensure that we have navigated using the top level process.
688 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
689 root->child_at(0)->current_frame_host()->GetSiteInstance());
692 // This test checks that killing a renderer process of a remote frame
693 // and then navigating some other frame to the same SiteInstance of the killed
694 // process works properly.
695 // This can be illustrated as follows,
696 // where 1/2/3 are FrameTreeNode-s and A/B are processes and B* is the killed
697 // B process:
699 // 1 A A A
700 // / \ -> / \ -> Kill B -> / \ -> Navigate 3 to B -> / \ .
701 // 2 3 B A B* A B* B
703 // Initially, node1.proxy_hosts_ = {B}
704 // After we kill B, we make sure B stays in node1.proxy_hosts_, then we navigate
705 // 3 to B and we expect that to complete normally.
706 // See http://crbug.com/432107.
708 // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
709 // site B and stays in not rendered state.
710 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
711 NavigateRemoteFrameToKilledProcess) {
712 GURL main_url(embedded_test_server()->GetURL(
713 "/frame_tree/page_with_two_frames.html"));
714 NavigateToURL(shell(), main_url);
716 // It is safe to obtain the root frame tree node here, as it doesn't change.
717 FrameTreeNode* root =
718 static_cast<WebContentsImpl*>(shell()->web_contents())->
719 GetFrameTree()->root();
721 TestNavigationObserver observer(shell()->web_contents());
722 ASSERT_EQ(2U, root->child_count());
724 // Make sure node2 points to the correct cross-site page.
725 GURL site_b_url = embedded_test_server()->GetURL("bar.com", "/title1.html");
726 FrameTreeNode* node2 = root->child_at(0);
727 EXPECT_EQ(site_b_url, node2->current_url());
729 // Kill that cross-site renderer.
730 RenderProcessHost* child_process =
731 node2->current_frame_host()->GetProcess();
732 RenderProcessHostWatcher crash_observer(
733 child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
734 child_process->Shutdown(0, false);
735 crash_observer.Wait();
737 // Now navigate the second iframe (node3) to the same site as the node2.
738 FrameTreeNode* node3 = root->child_at(1);
739 NavigateFrameToURL(node3, site_b_url);
740 EXPECT_TRUE(observer.last_navigation_succeeded());
741 EXPECT_EQ(site_b_url, observer.last_navigation_url());
744 // This test is similar to
745 // SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcess with
746 // addition that node2 also has a cross-origin frame to site C.
748 // 1 A A A
749 // / \ / \ / \ / \ .
750 // 2 3 -> B A -> Kill B -> B* A -> Navigate 3 -> B* B
751 // / /
752 // 4 C
754 // Initially, node1.proxy_hosts_ = {B, C}
755 // After we kill B, we make sure B stays in node1.proxy_hosts_, but
756 // C gets cleared from node1.proxy_hosts_.
758 // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
759 // site B and stays in not rendered state.
760 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
761 NavigateRemoteFrameToKilledProcessWithSubtree) {
762 GURL main_url(embedded_test_server()->GetURL(
763 "a.com", "/frame_tree/page_with_two_frames_nested.html"));
764 NavigateToURL(shell(), main_url);
766 // It is safe to obtain the root frame tree node here, as it doesn't change.
767 FrameTreeNode* root =
768 static_cast<WebContentsImpl*>(shell()->web_contents())->
769 GetFrameTree()->root();
770 TestNavigationObserver observer(shell()->web_contents());
772 ASSERT_EQ(2U, root->child_count());
774 GURL site_b_url(
775 embedded_test_server()->GetURL(
776 "bar.com", "/frame_tree/page_with_one_frame.html"));
777 // We can't use a TestNavigationObserver to verify the URL here,
778 // since the frame has children that may have clobbered it in the observer.
779 EXPECT_EQ(site_b_url, root->child_at(0)->current_url());
781 // Ensure that a new process is created for node2.
782 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
783 root->child_at(0)->current_frame_host()->GetSiteInstance());
784 // Ensure that a new process is *not* created for node3.
785 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
786 root->child_at(1)->current_frame_host()->GetSiteInstance());
788 ASSERT_EQ(1U, root->child_at(0)->child_count());
790 // Make sure node4 points to the correct cross-site page.
791 FrameTreeNode* node4 = root->child_at(0)->child_at(0);
792 GURL site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
793 EXPECT_EQ(site_c_url, node4->current_url());
795 // |site_instance_c| is expected to go away once we kill |child_process_b|
796 // below, so create a local scope so we can extend the lifetime of
797 // |site_instance_c| with a refptr.
799 // Initially each frame has proxies for the other sites.
800 EXPECT_EQ(
801 " Site A ------------ proxies for B C\n"
802 " |--Site B ------- proxies for A C\n"
803 " | +--Site C -- proxies for A B\n"
804 " +--Site A ------- proxies for B C\n"
805 "Where A = http://a.com/\n"
806 " B = http://bar.com/\n"
807 " C = http://baz.com/",
808 DepictFrameTree(root));
810 // Kill the render process for Site B.
811 RenderProcessHost* child_process_b =
812 root->child_at(0)->current_frame_host()->GetProcess();
813 RenderProcessHostWatcher crash_observer(
814 child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
815 child_process_b->Shutdown(0, false);
816 crash_observer.Wait();
818 // The Site C frame (a child of the crashed Site B frame) should go away,
819 // and there should be no remaining proxies for site C anywhere.
820 EXPECT_EQ(
821 " Site A ------------ proxies for B\n"
822 " |--Site B ------- proxies for A\n"
823 " +--Site A ------- proxies for B\n"
824 "Where A = http://a.com/\n"
825 " B = http://bar.com/ (no process)",
826 DepictFrameTree(root));
829 // Now navigate the second iframe (node3) to Site B also.
830 FrameTreeNode* node3 = root->child_at(1);
831 GURL url = embedded_test_server()->GetURL("bar.com", "/title1.html");
832 NavigateFrameToURL(node3, url);
833 EXPECT_TRUE(observer.last_navigation_succeeded());
834 EXPECT_EQ(url, observer.last_navigation_url());
836 EXPECT_EQ(
837 " Site A ------------ proxies for B\n"
838 " |--Site B ------- proxies for A\n"
839 " +--Site B ------- proxies for A\n"
840 "Where A = http://a.com/\n"
841 " B = http://bar.com/",
842 DepictFrameTree(root));
845 // Verify that killing a cross-site frame's process B and then navigating a
846 // frame to B correctly recreates all proxies in B.
848 // 1 A A A
849 // / | \ / | \ / | \ / | \ .
850 // 2 3 4 -> B A A -> Kill B -> B* A A -> B* B A
852 // After the last step, the test sends a postMessage from node 3 to node 4,
853 // verifying that a proxy for node 4 has been recreated in process B. This
854 // verifies the fix for https://crbug.com/478892.
855 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
856 NavigatingToKilledProcessRestoresAllProxies) {
857 // Navigate to a page with three frames: one cross-site and two same-site.
858 GURL main_url(embedded_test_server()->GetURL(
859 "a.com", "/frame_tree/page_with_three_frames.html"));
860 NavigateToURL(shell(), main_url);
862 // It is safe to obtain the root frame tree node here, as it doesn't change.
863 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
864 ->GetFrameTree()
865 ->root();
866 TestNavigationObserver observer(shell()->web_contents());
868 EXPECT_EQ(
869 " Site A ------------ proxies for B\n"
870 " |--Site B ------- proxies for A\n"
871 " |--Site A ------- proxies for B\n"
872 " +--Site A ------- proxies for B\n"
873 "Where A = http://a.com/\n"
874 " B = http://b.com/",
875 DepictFrameTree(root));
877 // Kill the first subframe's b.com renderer.
878 RenderProcessHost* child_process =
879 root->child_at(0)->current_frame_host()->GetProcess();
880 RenderProcessHostWatcher crash_observer(
881 child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
882 child_process->Shutdown(0, false);
883 crash_observer.Wait();
885 // Navigate the second subframe to b.com to recreate the b.com process.
886 GURL b_url = embedded_test_server()->GetURL("b.com", "/post_message.html");
887 NavigateFrameToURL(root->child_at(1), b_url);
888 // TODO(alexmos): This can be removed once TestFrameNavigationObserver is
889 // fixed to use DidFinishLoad.
890 EXPECT_TRUE(
891 WaitForRenderFrameReady(root->child_at(1)->current_frame_host()));
892 EXPECT_TRUE(observer.last_navigation_succeeded());
893 EXPECT_EQ(b_url, observer.last_navigation_url());
894 EXPECT_TRUE(root->child_at(1)->current_frame_host()->IsRenderFrameLive());
896 EXPECT_EQ(
897 " Site A ------------ proxies for B\n"
898 " |--Site B ------- proxies for A\n"
899 " |--Site B ------- proxies for A\n"
900 " +--Site A ------- proxies for B\n"
901 "Where A = http://a.com/\n"
902 " B = http://b.com/",
903 DepictFrameTree(root));
905 // Check that third subframe's proxy is available in the b.com process by
906 // sending it a postMessage from second subframe, and waiting for a reply.
907 PostMessageAndWaitForReply(root->child_at(1),
908 "postToSibling('subframe-msg','frame3')",
909 "\"done-frame2\"");
912 // Verify that proxy creation doesn't recreate a crashed process if no frame
913 // will be created in it.
915 // 1 A A A
916 // / | \ / | \ / | \ / | \ .
917 // 2 3 4 -> B A A -> Kill B -> B* A A -> B* A A
918 // \ .
919 // A
921 // The test kills process B (node 2), creates a child frame of node 4 in
922 // process A, and then checks that process B isn't resurrected to create a
923 // proxy for the new child frame. See https://crbug.com/476846.
924 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
925 CreateChildFrameAfterKillingProcess) {
926 // Navigate to a page with three frames: one cross-site and two same-site.
927 GURL main_url(embedded_test_server()->GetURL(
928 "a.com", "/frame_tree/page_with_three_frames.html"));
929 EXPECT_TRUE(NavigateToURL(shell(), main_url));
931 // It is safe to obtain the root frame tree node here, as it doesn't change.
932 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
933 ->GetFrameTree()
934 ->root();
936 EXPECT_EQ(
937 " Site A ------------ proxies for B\n"
938 " |--Site B ------- proxies for A\n"
939 " |--Site A ------- proxies for B\n"
940 " +--Site A ------- proxies for B\n"
941 "Where A = http://a.com/\n"
942 " B = http://b.com/",
943 DepictFrameTree(root));
944 SiteInstance* b_site_instance =
945 root->child_at(0)->current_frame_host()->GetSiteInstance();
947 // Kill the first subframe's renderer (B).
948 RenderProcessHost* child_process =
949 root->child_at(0)->current_frame_host()->GetProcess();
950 RenderProcessHostWatcher crash_observer(
951 child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
952 child_process->Shutdown(0, false);
953 crash_observer.Wait();
955 // Add a new child frame to the third subframe.
956 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 1);
957 EXPECT_TRUE(ExecuteScript(
958 root->child_at(2)->current_frame_host(),
959 "document.body.appendChild(document.createElement('iframe'));"));
960 frame_observer.Wait();
962 // The new frame should have a RenderFrameProxyHost for B, but it should not
963 // be alive, and B should still not have a process (verified by last line of
964 // expected DepictFrameTree output).
965 EXPECT_EQ(
966 " Site A ------------ proxies for B\n"
967 " |--Site B ------- proxies for A\n"
968 " |--Site A ------- proxies for B\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/ (no process)",
973 DepictFrameTree(root));
974 FrameTreeNode* grandchild = root->child_at(2)->child_at(0);
975 RenderFrameProxyHost* grandchild_rfph =
976 grandchild->render_manager()->GetRenderFrameProxyHost(b_site_instance);
977 EXPECT_FALSE(grandchild_rfph->is_render_frame_proxy_live());
979 // Navigate the second subframe to b.com to recreate process B.
980 TestNavigationObserver observer(shell()->web_contents());
981 GURL b_url = embedded_test_server()->GetURL("b.com", "/title1.html");
982 NavigateFrameToURL(root->child_at(1), b_url);
983 EXPECT_TRUE(observer.last_navigation_succeeded());
984 EXPECT_EQ(b_url, observer.last_navigation_url());
986 // Ensure that the grandchild RenderFrameProxy in B was created when process
987 // B was restored.
988 EXPECT_TRUE(grandchild_rfph->is_render_frame_proxy_live());
991 // In A-embed-B-embed-C scenario, verify that killing process B clears proxies
992 // of C from the tree.
994 // 1 A A
995 // / \ / \ / \ .
996 // 2 3 -> B A -> Kill B -> B* A
997 // / /
998 // 4 C
1000 // node1 is the root.
1001 // Initially, both node1.proxy_hosts_ and node3.proxy_hosts_ contain C.
1002 // After we kill B, make sure proxies for C are cleared.
1003 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1004 KillingRendererClearsDescendantProxies) {
1005 GURL main_url(embedded_test_server()->GetURL(
1006 "a.com", "/frame_tree/page_with_two_frames_nested.html"));
1007 NavigateToURL(shell(), main_url);
1009 // It is safe to obtain the root frame tree node here, as it doesn't change.
1010 FrameTreeNode* root =
1011 static_cast<WebContentsImpl*>(shell()->web_contents())->
1012 GetFrameTree()->root();
1013 ASSERT_EQ(2U, root->child_count());
1015 GURL site_b_url(
1016 embedded_test_server()->GetURL(
1017 "bar.com", "/frame_tree/page_with_one_frame.html"));
1018 // We can't use a TestNavigationObserver to verify the URL here,
1019 // since the frame has children that may have clobbered it in the observer.
1020 EXPECT_EQ(site_b_url, root->child_at(0)->current_url());
1022 // Ensure that a new process is created for node2.
1023 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1024 root->child_at(0)->current_frame_host()->GetSiteInstance());
1025 // Ensure that a new process is *not* created for node3.
1026 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
1027 root->child_at(1)->current_frame_host()->GetSiteInstance());
1029 ASSERT_EQ(1U, root->child_at(0)->child_count());
1031 // Make sure node4 points to the correct cross-site-page.
1032 FrameTreeNode* node4 = root->child_at(0)->child_at(0);
1033 GURL site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
1034 EXPECT_EQ(site_c_url, node4->current_url());
1036 // |site_instance_c|'s frames and proxies are expected to go away once we kill
1037 // |child_process_b| below.
1038 scoped_refptr<SiteInstanceImpl> site_instance_c =
1039 node4->current_frame_host()->GetSiteInstance();
1041 // Initially proxies for both B and C will be present in the root.
1042 EXPECT_EQ(
1043 " Site A ------------ proxies for B C\n"
1044 " |--Site B ------- proxies for A C\n"
1045 " | +--Site C -- proxies for A B\n"
1046 " +--Site A ------- proxies for B C\n"
1047 "Where A = http://a.com/\n"
1048 " B = http://bar.com/\n"
1049 " C = http://baz.com/",
1050 DepictFrameTree(root));
1052 EXPECT_GT(site_instance_c->active_frame_count(), 0U);
1054 // Kill process B.
1055 RenderProcessHost* child_process_b =
1056 root->child_at(0)->current_frame_host()->GetProcess();
1057 RenderProcessHostWatcher crash_observer(
1058 child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1059 child_process_b->Shutdown(0, false);
1060 crash_observer.Wait();
1062 // Make sure proxy C has gone from root.
1063 // Make sure proxy C has gone from node3 as well.
1064 // Make sure proxy B stays around in root and node3.
1065 EXPECT_EQ(
1066 " Site A ------------ proxies for B\n"
1067 " |--Site B ------- proxies for A\n"
1068 " +--Site A ------- proxies for B\n"
1069 "Where A = http://a.com/\n"
1070 " B = http://bar.com/ (no process)",
1071 DepictFrameTree(root));
1073 EXPECT_EQ(0U, site_instance_c->active_frame_count());
1076 // Crash a subframe and ensures its children are cleared from the FrameTree.
1077 // See http://crbug.com/338508.
1078 // TODO(creis): Disabled for flakiness; see http://crbug.com/405582.
1079 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DISABLED_CrashSubframe) {
1080 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1081 NavigateToURL(shell(), main_url);
1083 StartFrameAtDataURL();
1085 // Load cross-site page into iframe.
1086 EXPECT_TRUE(NavigateIframeToURL(
1087 shell()->web_contents(), "test",
1088 embedded_test_server()->GetURL("/cross-site/foo.com/title2.html")));
1090 // Check the subframe process.
1091 FrameTreeNode* root =
1092 static_cast<WebContentsImpl*>(shell()->web_contents())->
1093 GetFrameTree()->root();
1094 ASSERT_EQ(2U, root->child_count());
1095 FrameTreeNode* child = root->child_at(0);
1096 EXPECT_EQ(main_url, root->current_url());
1097 EXPECT_EQ("foo.com", child->current_url().host());
1098 EXPECT_EQ("/title2.html", child->current_url().path());
1100 EXPECT_TRUE(
1101 child->current_frame_host()->render_view_host()->IsRenderViewLive());
1102 EXPECT_TRUE(child->current_frame_host()->IsRenderFrameLive());
1104 // Crash the subframe process.
1105 RenderProcessHost* root_process = root->current_frame_host()->GetProcess();
1106 RenderProcessHost* child_process = child->current_frame_host()->GetProcess();
1108 RenderProcessHostWatcher crash_observer(
1109 child_process,
1110 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1111 child_process->Shutdown(0, false);
1112 crash_observer.Wait();
1115 // Ensure that the child frame still exists but has been cleared.
1116 EXPECT_EQ(2U, root->child_count());
1117 EXPECT_EQ(main_url, root->current_url());
1118 EXPECT_EQ(GURL(), child->current_url());
1120 EXPECT_FALSE(
1121 child->current_frame_host()->render_view_host()->IsRenderViewLive());
1122 EXPECT_FALSE(child->current_frame_host()->IsRenderFrameLive());
1123 EXPECT_FALSE(child->current_frame_host()->render_frame_created_);
1125 // Now crash the top-level page to clear the child frame.
1127 RenderProcessHostWatcher crash_observer(
1128 root_process,
1129 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1130 root_process->Shutdown(0, false);
1131 crash_observer.Wait();
1133 EXPECT_EQ(0U, root->child_count());
1134 EXPECT_EQ(GURL(), root->current_url());
1137 // When a new subframe is added, related SiteInstances that can reach the
1138 // subframe should create proxies for it (https://crbug.com/423587). This test
1139 // checks that if A embeds B and later adds a new subframe A2, A2 gets a proxy
1140 // in B's process.
1141 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CreateProxiesForNewFrames) {
1142 GURL main_url(embedded_test_server()->GetURL(
1143 "b.com", "/frame_tree/page_with_one_frame.html"));
1144 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1146 // It is safe to obtain the root frame tree node here, as it doesn't change.
1147 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1148 ->GetFrameTree()
1149 ->root();
1150 ASSERT_EQ(1U, root->child_count());
1152 // Make sure the frame starts out at the correct cross-site URL.
1153 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"),
1154 root->child_at(0)->current_url());
1156 EXPECT_EQ(
1157 " Site A ------------ proxies for B\n"
1158 " +--Site B ------- proxies for A\n"
1159 "Where A = http://b.com/\n"
1160 " B = http://baz.com/",
1161 DepictFrameTree(root));
1163 // Add a new child frame to the top-level frame.
1164 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 1);
1165 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1166 "window.domAutomationController.send("
1167 " addFrame('data:text/html,foo'));"));
1168 frame_observer.Wait();
1170 // The new frame should have a proxy in Site B, for use by the old frame.
1171 EXPECT_EQ(
1172 " Site A ------------ proxies for B\n"
1173 " |--Site B ------- proxies for A\n"
1174 " +--Site A ------- proxies for B\n"
1175 "Where A = http://b.com/\n"
1176 " B = http://baz.com/",
1177 DepictFrameTree(root));
1180 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
1181 // security checks are back in place.
1182 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
1183 // on Android (http://crbug.com/187570).
1184 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1185 DISABLED_CrossSiteIframeRedirectOnce) {
1186 ASSERT_TRUE(test_server()->Start());
1187 net::SpawnedTestServer https_server(
1188 net::SpawnedTestServer::TYPE_HTTPS,
1189 net::SpawnedTestServer::kLocalhost,
1190 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
1191 ASSERT_TRUE(https_server.Start());
1193 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
1194 GURL http_url(test_server()->GetURL("files/title1.html"));
1195 GURL https_url(https_server.GetURL("files/title1.html"));
1197 NavigateToURL(shell(), main_url);
1199 TestNavigationObserver observer(shell()->web_contents());
1201 // Load cross-site client-redirect page into Iframe.
1202 // Should be blocked.
1203 GURL client_redirect_https_url(https_server.GetURL(
1204 "client-redirect?files/title1.html"));
1205 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1206 client_redirect_https_url));
1207 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
1208 EXPECT_EQ(observer.last_navigation_url(), client_redirect_https_url);
1209 EXPECT_FALSE(observer.last_navigation_succeeded());
1213 // Load cross-site server-redirect page into Iframe,
1214 // which redirects to same-site page.
1215 GURL server_redirect_http_url(https_server.GetURL(
1216 "server-redirect?" + http_url.spec()));
1217 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1218 server_redirect_http_url));
1219 EXPECT_EQ(observer.last_navigation_url(), http_url);
1220 EXPECT_TRUE(observer.last_navigation_succeeded());
1224 // Load cross-site server-redirect page into Iframe,
1225 // which redirects to cross-site page.
1226 GURL server_redirect_http_url(https_server.GetURL(
1227 "server-redirect?files/title1.html"));
1228 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1229 server_redirect_http_url));
1230 // DidFailProvisionalLoad when navigating to https_url.
1231 EXPECT_EQ(observer.last_navigation_url(), https_url);
1232 EXPECT_FALSE(observer.last_navigation_succeeded());
1236 // Load same-site server-redirect page into Iframe,
1237 // which redirects to cross-site page.
1238 GURL server_redirect_http_url(test_server()->GetURL(
1239 "server-redirect?" + https_url.spec()));
1240 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1241 server_redirect_http_url));
1243 EXPECT_EQ(observer.last_navigation_url(), https_url);
1244 EXPECT_FALSE(observer.last_navigation_succeeded());
1248 // Load same-site client-redirect page into Iframe,
1249 // which redirects to cross-site page.
1250 GURL client_redirect_http_url(test_server()->GetURL(
1251 "client-redirect?" + https_url.spec()));
1253 RedirectNotificationObserver load_observer2(
1254 NOTIFICATION_LOAD_STOP,
1255 Source<NavigationController>(
1256 &shell()->web_contents()->GetController()));
1258 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1259 client_redirect_http_url));
1261 // Same-site Client-Redirect Page should be loaded successfully.
1262 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
1263 EXPECT_TRUE(observer.last_navigation_succeeded());
1265 // Redirecting to Cross-site Page should be blocked.
1266 load_observer2.Wait();
1267 EXPECT_EQ(observer.last_navigation_url(), https_url);
1268 EXPECT_FALSE(observer.last_navigation_succeeded());
1272 // Load same-site server-redirect page into Iframe,
1273 // which redirects to same-site page.
1274 GURL server_redirect_http_url(test_server()->GetURL(
1275 "server-redirect?files/title1.html"));
1276 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1277 server_redirect_http_url));
1278 EXPECT_EQ(observer.last_navigation_url(), http_url);
1279 EXPECT_TRUE(observer.last_navigation_succeeded());
1283 // Load same-site client-redirect page into Iframe,
1284 // which redirects to same-site page.
1285 GURL client_redirect_http_url(test_server()->GetURL(
1286 "client-redirect?" + http_url.spec()));
1287 RedirectNotificationObserver load_observer2(
1288 NOTIFICATION_LOAD_STOP,
1289 Source<NavigationController>(
1290 &shell()->web_contents()->GetController()));
1292 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1293 client_redirect_http_url));
1295 // Same-site Client-Redirect Page should be loaded successfully.
1296 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
1297 EXPECT_TRUE(observer.last_navigation_succeeded());
1299 // Redirecting to Same-site Page should be loaded successfully.
1300 load_observer2.Wait();
1301 EXPECT_EQ(observer.last_navigation_url(), http_url);
1302 EXPECT_TRUE(observer.last_navigation_succeeded());
1306 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
1307 // security checks are back in place.
1308 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
1309 // on Android (http://crbug.com/187570).
1310 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1311 DISABLED_CrossSiteIframeRedirectTwice) {
1312 ASSERT_TRUE(test_server()->Start());
1313 net::SpawnedTestServer https_server(
1314 net::SpawnedTestServer::TYPE_HTTPS,
1315 net::SpawnedTestServer::kLocalhost,
1316 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
1317 ASSERT_TRUE(https_server.Start());
1319 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
1320 GURL http_url(test_server()->GetURL("files/title1.html"));
1321 GURL https_url(https_server.GetURL("files/title1.html"));
1323 NavigateToURL(shell(), main_url);
1325 TestNavigationObserver observer(shell()->web_contents());
1327 // Load client-redirect page pointing to a cross-site client-redirect page,
1328 // which eventually redirects back to same-site page.
1329 GURL client_redirect_https_url(https_server.GetURL(
1330 "client-redirect?" + http_url.spec()));
1331 GURL client_redirect_http_url(test_server()->GetURL(
1332 "client-redirect?" + client_redirect_https_url.spec()));
1334 // We should wait until second client redirect get cancelled.
1335 RedirectNotificationObserver load_observer2(
1336 NOTIFICATION_LOAD_STOP,
1337 Source<NavigationController>(
1338 &shell()->web_contents()->GetController()));
1340 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1341 client_redirect_http_url));
1343 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
1344 load_observer2.Wait();
1345 EXPECT_EQ(observer.last_navigation_url(), client_redirect_https_url);
1346 EXPECT_FALSE(observer.last_navigation_succeeded());
1350 // Load server-redirect page pointing to a cross-site server-redirect page,
1351 // which eventually redirect back to same-site page.
1352 GURL server_redirect_https_url(https_server.GetURL(
1353 "server-redirect?" + http_url.spec()));
1354 GURL server_redirect_http_url(test_server()->GetURL(
1355 "server-redirect?" + server_redirect_https_url.spec()));
1356 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1357 server_redirect_http_url));
1358 EXPECT_EQ(observer.last_navigation_url(), http_url);
1359 EXPECT_TRUE(observer.last_navigation_succeeded());
1363 // Load server-redirect page pointing to a cross-site server-redirect page,
1364 // which eventually redirects back to cross-site page.
1365 GURL server_redirect_https_url(https_server.GetURL(
1366 "server-redirect?" + https_url.spec()));
1367 GURL server_redirect_http_url(test_server()->GetURL(
1368 "server-redirect?" + server_redirect_https_url.spec()));
1369 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1370 server_redirect_http_url));
1372 // DidFailProvisionalLoad when navigating to https_url.
1373 EXPECT_EQ(observer.last_navigation_url(), https_url);
1374 EXPECT_FALSE(observer.last_navigation_succeeded());
1378 // Load server-redirect page pointing to a cross-site client-redirect page,
1379 // which eventually redirects back to same-site page.
1380 GURL client_redirect_http_url(https_server.GetURL(
1381 "client-redirect?" + http_url.spec()));
1382 GURL server_redirect_http_url(test_server()->GetURL(
1383 "server-redirect?" + client_redirect_http_url.spec()));
1384 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1385 server_redirect_http_url));
1387 // DidFailProvisionalLoad when navigating to client_redirect_http_url.
1388 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
1389 EXPECT_FALSE(observer.last_navigation_succeeded());
1393 // Ensure that when navigating a frame cross-process RenderFrameProxyHosts are
1394 // created in the FrameTree skipping the subtree of the navigating frame.
1395 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1396 ProxyCreationSkipsSubtree) {
1397 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1398 NavigateToURL(shell(), main_url);
1400 // It is safe to obtain the root frame tree node here, as it doesn't change.
1401 FrameTreeNode* root =
1402 static_cast<WebContentsImpl*>(shell()->web_contents())->
1403 GetFrameTree()->root();
1405 EXPECT_TRUE(root->child_at(1) != NULL);
1406 EXPECT_EQ(2U, root->child_at(1)->child_count());
1409 // Load same-site page into iframe.
1410 TestNavigationObserver observer(shell()->web_contents());
1411 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
1412 NavigateFrameToURL(root->child_at(0), http_url);
1413 EXPECT_EQ(http_url, observer.last_navigation_url());
1414 EXPECT_TRUE(observer.last_navigation_succeeded());
1415 EXPECT_EQ(
1416 " Site A\n"
1417 " |--Site A\n"
1418 " +--Site A\n"
1419 " |--Site A\n"
1420 " +--Site A\n"
1421 " +--Site A\n"
1422 "Where A = http://127.0.0.1/",
1423 DepictFrameTree(root));
1426 // Create the cross-site URL to navigate to.
1427 GURL cross_site_url =
1428 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html");
1430 // Load cross-site page into the second iframe without waiting for the
1431 // navigation to complete. Once LoadURLWithParams returns, we would expect
1432 // proxies to have been created in the frame tree, but children of the
1433 // navigating frame to still be present. The reason is that we don't run the
1434 // message loop, so no IPCs that alter the frame tree can be processed.
1435 FrameTreeNode* child = root->child_at(1);
1436 SiteInstance* site = NULL;
1437 bool browser_side_navigation =
1438 base::CommandLine::ForCurrentProcess()->HasSwitch(
1439 switches::kEnableBrowserSideNavigation);
1440 std::string cross_site_rfh_type =
1441 browser_side_navigation ? "speculative" : "pending";
1443 TestNavigationObserver observer(shell()->web_contents());
1444 TestFrameNavigationObserver navigation_observer(child);
1445 NavigationController::LoadURLParams params(cross_site_url);
1446 params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
1447 params.frame_tree_node_id = child->frame_tree_node_id();
1448 child->navigator()->GetController()->LoadURLWithParams(params);
1450 if (browser_side_navigation) {
1451 site = child->render_manager()
1452 ->speculative_frame_host_for_testing()
1453 ->GetSiteInstance();
1454 } else {
1455 site = child->render_manager()->pending_frame_host()->GetSiteInstance();
1457 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site);
1459 std::string tree = base::StringPrintf(
1460 " Site A ------------ proxies for B\n"
1461 " |--Site A ------- proxies for B\n"
1462 " +--Site A (B %s)\n"
1463 " |--Site A\n"
1464 " +--Site A\n"
1465 " +--Site A\n"
1466 "Where A = http://127.0.0.1/\n"
1467 " B = http://foo.com/",
1468 cross_site_rfh_type.c_str());
1469 EXPECT_EQ(tree, DepictFrameTree(root));
1471 // Now that the verification is done, run the message loop and wait for the
1472 // navigation to complete.
1473 navigation_observer.Wait();
1474 EXPECT_FALSE(child->render_manager()->pending_frame_host());
1475 EXPECT_TRUE(observer.last_navigation_succeeded());
1476 EXPECT_EQ(cross_site_url, observer.last_navigation_url());
1478 EXPECT_EQ(
1479 " Site A ------------ proxies for B\n"
1480 " |--Site A ------- proxies for B\n"
1481 " +--Site B ------- proxies for A\n"
1482 "Where A = http://127.0.0.1/\n"
1483 " B = http://foo.com/",
1484 DepictFrameTree(root));
1487 // Load another cross-site page into the same iframe.
1488 cross_site_url = embedded_test_server()->GetURL("bar.com", "/title2.html");
1490 // Perform the same checks as the first cross-site navigation, since
1491 // there have been issues in subsequent cross-site navigations. Also ensure
1492 // that the SiteInstance has properly changed.
1493 // TODO(nasko): Once we have proper cleanup of resources, add code to
1494 // verify that the intermediate SiteInstance/RenderFrameHost have been
1495 // properly cleaned up.
1496 TestNavigationObserver observer(shell()->web_contents());
1497 TestFrameNavigationObserver navigation_observer(child);
1498 NavigationController::LoadURLParams params(cross_site_url);
1499 params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
1500 params.frame_tree_node_id = child->frame_tree_node_id();
1501 child->navigator()->GetController()->LoadURLWithParams(params);
1503 SiteInstance* site2;
1504 if (browser_side_navigation) {
1505 site2 = child->render_manager()
1506 ->speculative_frame_host_for_testing()
1507 ->GetSiteInstance();
1508 } else {
1509 site2 = child->render_manager()->pending_frame_host()->GetSiteInstance();
1511 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site2);
1512 EXPECT_NE(site, site2);
1514 std::string tree = base::StringPrintf(
1515 " Site A ------------ proxies for B C\n"
1516 " |--Site A ------- proxies for B C\n"
1517 " +--Site B (C %s) -- proxies for A\n"
1518 "Where A = http://127.0.0.1/\n"
1519 " B = http://foo.com/\n"
1520 " C = http://bar.com/",
1521 cross_site_rfh_type.c_str());
1522 EXPECT_EQ(tree, DepictFrameTree(root));
1524 navigation_observer.Wait();
1525 EXPECT_TRUE(observer.last_navigation_succeeded());
1526 EXPECT_EQ(cross_site_url, observer.last_navigation_url());
1527 EXPECT_EQ(0U, child->child_count());
1531 // Verify that origin replication works for an A-embed-B-embed-C hierarchy.
1532 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OriginReplication) {
1533 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1534 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1536 // It is safe to obtain the root frame tree node here, as it doesn't change.
1537 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1538 ->GetFrameTree()
1539 ->root();
1541 TestNavigationObserver observer(shell()->web_contents());
1543 // Navigate the first subframe to a cross-site page with two subframes.
1544 GURL foo_url(
1545 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
1546 NavigateFrameToURL(root->child_at(0), foo_url);
1547 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1549 // We can't use a TestNavigationObserver to verify the URL here,
1550 // since the frame has children that may have clobbered it in the observer.
1551 EXPECT_EQ(foo_url, root->child_at(0)->current_url());
1553 // Ensure that a new process is created for the subframe.
1554 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1555 root->child_at(0)->current_frame_host()->GetSiteInstance());
1557 // Load cross-site page into subframe's subframe.
1558 ASSERT_EQ(2U, root->child_at(0)->child_count());
1559 GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
1560 NavigateFrameToURL(root->child_at(0)->child_at(0), bar_url);
1561 EXPECT_TRUE(observer.last_navigation_succeeded());
1562 EXPECT_EQ(bar_url, observer.last_navigation_url());
1564 // Check that a new process is created and is different from the top one and
1565 // the middle one.
1566 FrameTreeNode* bottom_child = root->child_at(0)->child_at(0);
1567 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1568 bottom_child->current_frame_host()->GetSiteInstance());
1569 EXPECT_NE(root->child_at(0)->current_frame_host()->GetSiteInstance(),
1570 bottom_child->current_frame_host()->GetSiteInstance());
1572 // Check that foo.com frame's location.ancestorOrigins contains the correct
1573 // origin for the parent. The origin should have been replicated as part of
1574 // the ViewMsg_New message that created the parent's RenderFrameProxy in
1575 // foo.com's process.
1576 int ancestor_origins_length = 0;
1577 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1578 root->child_at(0)->current_frame_host(),
1579 "window.domAutomationController.send(location.ancestorOrigins.length);",
1580 &ancestor_origins_length));
1581 EXPECT_EQ(1, ancestor_origins_length);
1582 std::string result;
1583 EXPECT_TRUE(ExecuteScriptAndExtractString(
1584 root->child_at(0)->current_frame_host(),
1585 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1586 &result));
1587 EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
1589 // Check that bar.com frame's location.ancestorOrigins contains the correct
1590 // origin for its two ancestors. The topmost parent origin should be
1591 // replicated as part of ViewMsg_New, and the middle frame (foo.com's) origin
1592 // should be replicated as part of FrameMsg_NewFrameProxy sent for foo.com's
1593 // frame in bar.com's process.
1594 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1595 bottom_child->current_frame_host(),
1596 "window.domAutomationController.send(location.ancestorOrigins.length);",
1597 &ancestor_origins_length));
1598 EXPECT_EQ(2, ancestor_origins_length);
1599 EXPECT_TRUE(ExecuteScriptAndExtractString(
1600 bottom_child->current_frame_host(),
1601 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1602 &result));
1603 EXPECT_EQ(result + "/", foo_url.GetOrigin().spec());
1604 EXPECT_TRUE(ExecuteScriptAndExtractString(
1605 bottom_child->current_frame_host(),
1606 "window.domAutomationController.send(location.ancestorOrigins[1]);",
1607 &result));
1608 EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
1611 // Check that iframe sandbox flags are replicated correctly.
1612 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SandboxFlagsReplication) {
1613 GURL main_url(embedded_test_server()->GetURL("/sandboxed_frames.html"));
1614 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1616 // It is safe to obtain the root frame tree node here, as it doesn't change.
1617 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1618 ->GetFrameTree()
1619 ->root();
1621 TestNavigationObserver observer(shell()->web_contents());
1623 // Navigate the second (sandboxed) subframe to a cross-site page with a
1624 // subframe.
1625 GURL foo_url(
1626 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
1627 NavigateFrameToURL(root->child_at(1), foo_url);
1628 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1630 // We can't use a TestNavigationObserver to verify the URL here,
1631 // since the frame has children that may have clobbered it in the observer.
1632 EXPECT_EQ(foo_url, root->child_at(1)->current_url());
1634 // Load cross-site page into subframe's subframe.
1635 ASSERT_EQ(2U, root->child_at(1)->child_count());
1636 GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
1637 NavigateFrameToURL(root->child_at(1)->child_at(0), bar_url);
1638 EXPECT_TRUE(observer.last_navigation_succeeded());
1639 EXPECT_EQ(bar_url, observer.last_navigation_url());
1641 // Opening a popup in the sandboxed foo.com iframe should fail.
1642 bool success = false;
1643 EXPECT_TRUE(
1644 ExecuteScriptAndExtractBool(root->child_at(1)->current_frame_host(),
1645 "window.domAutomationController.send("
1646 "!window.open('data:text/html,dataurl'));",
1647 &success));
1648 EXPECT_TRUE(success);
1649 EXPECT_EQ(1u, Shell::windows().size());
1651 // Opening a popup in a frame whose parent is sandboxed should also fail.
1652 // Here, bar.com frame's sandboxed parent frame is a remote frame in
1653 // bar.com's process.
1654 success = false;
1655 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1656 root->child_at(1)->child_at(0)->current_frame_host(),
1657 "window.domAutomationController.send("
1658 "!window.open('data:text/html,dataurl'));",
1659 &success));
1660 EXPECT_TRUE(success);
1661 EXPECT_EQ(1u, Shell::windows().size());
1663 // Same, but now try the case where bar.com frame's sandboxed parent is a
1664 // local frame in bar.com's process.
1665 success = false;
1666 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1667 root->child_at(2)->child_at(0)->current_frame_host(),
1668 "window.domAutomationController.send("
1669 "!window.open('data:text/html,dataurl'));",
1670 &success));
1671 EXPECT_TRUE(success);
1672 EXPECT_EQ(1u, Shell::windows().size());
1674 // Check that foo.com frame's location.ancestorOrigins contains the correct
1675 // origin for the parent, which should be unaffected by sandboxing.
1676 int ancestor_origins_length = 0;
1677 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1678 root->child_at(1)->current_frame_host(),
1679 "window.domAutomationController.send(location.ancestorOrigins.length);",
1680 &ancestor_origins_length));
1681 EXPECT_EQ(1, ancestor_origins_length);
1682 std::string result;
1683 EXPECT_TRUE(ExecuteScriptAndExtractString(
1684 root->child_at(1)->current_frame_host(),
1685 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1686 &result));
1687 EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
1689 // Now check location.ancestorOrigins for the bar.com frame. The middle frame
1690 // (foo.com's) origin should be unique, since that frame is sandboxed, and
1691 // the top frame should match |main_url|.
1692 FrameTreeNode* bottom_child = root->child_at(1)->child_at(0);
1693 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1694 bottom_child->current_frame_host(),
1695 "window.domAutomationController.send(location.ancestorOrigins.length);",
1696 &ancestor_origins_length));
1697 EXPECT_EQ(2, ancestor_origins_length);
1698 EXPECT_TRUE(ExecuteScriptAndExtractString(
1699 bottom_child->current_frame_host(),
1700 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1701 &result));
1702 EXPECT_EQ("null", result);
1703 EXPECT_TRUE(ExecuteScriptAndExtractString(
1704 bottom_child->current_frame_host(),
1705 "window.domAutomationController.send(location.ancestorOrigins[1]);",
1706 &result));
1707 EXPECT_EQ(main_url.GetOrigin().spec(), result + "/");
1710 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
1711 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicSandboxFlags) {
1712 GURL main_url(
1713 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
1714 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1716 // It is safe to obtain the root frame tree node here, as it doesn't change.
1717 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1718 ->GetFrameTree()
1719 ->root();
1721 TestNavigationObserver observer(shell()->web_contents());
1722 ASSERT_EQ(2U, root->child_count());
1724 // Make sure first frame starts out at the correct cross-site page.
1725 EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"),
1726 root->child_at(0)->current_url());
1728 // Navigate second frame to another cross-site page.
1729 GURL baz_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
1730 NavigateFrameToURL(root->child_at(1), baz_url);
1731 EXPECT_TRUE(observer.last_navigation_succeeded());
1732 EXPECT_EQ(baz_url, observer.last_navigation_url());
1734 // Both frames should not be sandboxed to start with.
1735 EXPECT_EQ(blink::WebSandboxFlags::None,
1736 root->child_at(0)->current_replication_state().sandbox_flags);
1737 EXPECT_EQ(blink::WebSandboxFlags::None,
1738 root->child_at(0)->effective_sandbox_flags());
1739 EXPECT_EQ(blink::WebSandboxFlags::None,
1740 root->child_at(1)->current_replication_state().sandbox_flags);
1741 EXPECT_EQ(blink::WebSandboxFlags::None,
1742 root->child_at(1)->effective_sandbox_flags());
1744 // Dynamically update sandbox flags for the first frame.
1745 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1746 "window.domAutomationController.send("
1747 "document.querySelector('iframe').sandbox="
1748 "'allow-scripts');"));
1750 // Check that updated sandbox flags are propagated to browser process.
1751 // The new flags should be set in current_replication_state(), while
1752 // effective_sandbox_flags() should still reflect the old flags, because
1753 // sandbox flag updates take place only after navigations. "allow-scripts"
1754 // resets both SandboxFlags::Scripts and SandboxFlags::AutomaticFeatures bits
1755 // per blink::parseSandboxPolicy().
1756 blink::WebSandboxFlags expected_flags =
1757 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
1758 ~blink::WebSandboxFlags::AutomaticFeatures;
1759 EXPECT_EQ(expected_flags,
1760 root->child_at(0)->current_replication_state().sandbox_flags);
1761 EXPECT_EQ(blink::WebSandboxFlags::None,
1762 root->child_at(0)->effective_sandbox_flags());
1764 // Navigate the first frame to a page on the same site. The new sandbox
1765 // flags should take effect.
1766 GURL bar_url(
1767 embedded_test_server()->GetURL("bar.com", "/frame_tree/2-4.html"));
1768 NavigateFrameToURL(root->child_at(0), bar_url);
1769 // (The new page has a subframe; wait for it to load as well.)
1770 ASSERT_TRUE(WaitForLoadStop(shell()->web_contents()));
1771 EXPECT_EQ(bar_url, root->child_at(0)->current_url());
1772 ASSERT_EQ(1U, root->child_at(0)->child_count());
1774 EXPECT_EQ(
1775 " Site A ------------ proxies for B C\n"
1776 " |--Site B ------- proxies for A C\n"
1777 " | +--Site B -- proxies for A C\n"
1778 " +--Site C ------- proxies for A B\n"
1779 "Where A = http://127.0.0.1/\n"
1780 " B = http://bar.com/\n"
1781 " C = http://baz.com/",
1782 DepictFrameTree(root));
1784 // Confirm that the browser process has updated the frame's current sandbox
1785 // flags.
1786 EXPECT_EQ(expected_flags,
1787 root->child_at(0)->current_replication_state().sandbox_flags);
1788 EXPECT_EQ(expected_flags, root->child_at(0)->effective_sandbox_flags());
1790 // Opening a popup in the now-sandboxed frame should fail.
1791 bool success = false;
1792 EXPECT_TRUE(
1793 ExecuteScriptAndExtractBool(root->child_at(0)->current_frame_host(),
1794 "window.domAutomationController.send("
1795 "!window.open('data:text/html,dataurl'));",
1796 &success));
1797 EXPECT_TRUE(success);
1798 EXPECT_EQ(1u, Shell::windows().size());
1800 // Navigate the child of the now-sandboxed frame to a page on baz.com. The
1801 // child should inherit the latest sandbox flags from its parent frame, which
1802 // is currently a proxy in baz.com's renderer process. This checks that the
1803 // proxies of |root->child_at(0)| were also updated with the latest sandbox
1804 // flags.
1805 GURL baz_child_url(embedded_test_server()->GetURL("baz.com", "/title2.html"));
1806 NavigateFrameToURL(root->child_at(0)->child_at(0), baz_child_url);
1807 EXPECT_TRUE(observer.last_navigation_succeeded());
1808 EXPECT_EQ(baz_child_url, observer.last_navigation_url());
1810 EXPECT_EQ(
1811 " Site A ------------ proxies for B C\n"
1812 " |--Site B ------- proxies for A C\n"
1813 " | +--Site C -- proxies for A B\n"
1814 " +--Site C ------- proxies for A B\n"
1815 "Where A = http://127.0.0.1/\n"
1816 " B = http://bar.com/\n"
1817 " C = http://baz.com/",
1818 DepictFrameTree(root));
1820 // Opening a popup in the child of a sandboxed frame should fail.
1821 success = false;
1822 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1823 root->child_at(0)->child_at(0)->current_frame_host(),
1824 "window.domAutomationController.send("
1825 "!window.open('data:text/html,dataurl'));",
1826 &success));
1827 EXPECT_TRUE(success);
1828 EXPECT_EQ(1u, Shell::windows().size());
1831 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
1832 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1833 DynamicSandboxFlagsRemoteToLocal) {
1834 GURL main_url(
1835 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
1836 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1838 // It is safe to obtain the root frame tree node here, as it doesn't change.
1839 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1840 ->GetFrameTree()
1841 ->root();
1843 TestNavigationObserver observer(shell()->web_contents());
1844 ASSERT_EQ(2U, root->child_count());
1846 // Make sure the two frames starts out at correct URLs.
1847 EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"),
1848 root->child_at(0)->current_url());
1849 EXPECT_EQ(embedded_test_server()->GetURL("/title1.html"),
1850 root->child_at(1)->current_url());
1852 // Update the second frame's sandbox flags.
1853 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1854 "window.domAutomationController.send("
1855 "document.querySelectorAll('iframe')[1].sandbox="
1856 "'allow-scripts');"));
1858 // Check that the current sandbox flags are updated but the effective
1859 // sandbox flags are not.
1860 blink::WebSandboxFlags expected_flags =
1861 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
1862 ~blink::WebSandboxFlags::AutomaticFeatures;
1863 EXPECT_EQ(expected_flags,
1864 root->child_at(1)->current_replication_state().sandbox_flags);
1865 EXPECT_EQ(blink::WebSandboxFlags::None,
1866 root->child_at(1)->effective_sandbox_flags());
1868 // Navigate the second subframe to a page on bar.com. This will trigger a
1869 // remote-to-local frame swap in bar.com's process. The target page has
1870 // another frame, so use TestFrameNavigationObserver to wait for all frames
1871 // to be loaded.
1872 TestFrameNavigationObserver frame_observer(root->child_at(1), 2);
1873 GURL bar_url(embedded_test_server()->GetURL(
1874 "bar.com", "/frame_tree/page_with_one_frame.html"));
1875 NavigateFrameToURL(root->child_at(1), bar_url);
1876 frame_observer.Wait();
1877 EXPECT_EQ(bar_url, root->child_at(1)->current_url());
1878 ASSERT_EQ(1U, root->child_at(1)->child_count());
1880 // Confirm that the browser process has updated the current sandbox flags.
1881 EXPECT_EQ(expected_flags,
1882 root->child_at(1)->current_replication_state().sandbox_flags);
1883 EXPECT_EQ(expected_flags, root->child_at(1)->effective_sandbox_flags());
1885 // Opening a popup in the sandboxed second frame should fail.
1886 bool success = false;
1887 EXPECT_TRUE(
1888 ExecuteScriptAndExtractBool(root->child_at(1)->current_frame_host(),
1889 "window.domAutomationController.send("
1890 "!window.open('data:text/html,dataurl'));",
1891 &success));
1892 EXPECT_TRUE(success);
1893 EXPECT_EQ(1u, Shell::windows().size());
1895 // Make sure that the child frame inherits the sandbox flags of its
1896 // now-sandboxed parent frame.
1897 success = false;
1898 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1899 root->child_at(1)->child_at(0)->current_frame_host(),
1900 "window.domAutomationController.send("
1901 "!window.open('data:text/html,dataurl'));",
1902 &success));
1903 EXPECT_TRUE(success);
1904 EXPECT_EQ(1u, Shell::windows().size());
1907 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
1908 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1909 DynamicSandboxFlagsRendererInitiatedNavigation) {
1910 GURL main_url(
1911 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
1912 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1914 // It is safe to obtain the root frame tree node here, as it doesn't change.
1915 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1916 ->GetFrameTree()
1917 ->root();
1919 TestNavigationObserver observer(shell()->web_contents());
1920 ASSERT_EQ(1U, root->child_count());
1922 // Make sure the frame starts out at the correct cross-site page.
1923 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"),
1924 root->child_at(0)->current_url());
1926 // The frame should not be sandboxed to start with.
1927 EXPECT_EQ(blink::WebSandboxFlags::None,
1928 root->child_at(0)->current_replication_state().sandbox_flags);
1929 EXPECT_EQ(blink::WebSandboxFlags::None,
1930 root->child_at(0)->effective_sandbox_flags());
1932 // Dynamically update the frame's sandbox flags.
1933 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1934 "window.domAutomationController.send("
1935 "document.querySelector('iframe').sandbox="
1936 "'allow-scripts');"));
1938 // Check that updated sandbox flags are propagated to browser process.
1939 // The new flags should be set in current_replication_state(), while
1940 // effective_sandbox_flags() should still reflect the old flags, because
1941 // sandbox flag updates take place only after navigations. "allow-scripts"
1942 // resets both SandboxFlags::Scripts and SandboxFlags::AutomaticFeatures bits
1943 // per blink::parseSandboxPolicy().
1944 blink::WebSandboxFlags expected_flags =
1945 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
1946 ~blink::WebSandboxFlags::AutomaticFeatures;
1947 EXPECT_EQ(expected_flags,
1948 root->child_at(0)->current_replication_state().sandbox_flags);
1949 EXPECT_EQ(blink::WebSandboxFlags::None,
1950 root->child_at(0)->effective_sandbox_flags());
1952 // Perform a renderer-initiated same-site navigation in the first frame. The
1953 // new sandbox flags should take effect.
1954 TestFrameNavigationObserver frame_observer(root->child_at(0));
1955 ASSERT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
1956 "window.location.href='/title2.html'"));
1957 frame_observer.Wait();
1958 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title2.html"),
1959 root->child_at(0)->current_url());
1961 // Confirm that the browser process has updated the frame's current sandbox
1962 // flags.
1963 EXPECT_EQ(expected_flags,
1964 root->child_at(0)->current_replication_state().sandbox_flags);
1965 EXPECT_EQ(expected_flags, root->child_at(0)->effective_sandbox_flags());
1967 // Opening a popup in the now-sandboxed frame should fail.
1968 bool success = false;
1969 EXPECT_TRUE(
1970 ExecuteScriptAndExtractBool(root->child_at(0)->current_frame_host(),
1971 "window.domAutomationController.send("
1972 "!window.open('data:text/html,dataurl'));",
1973 &success));
1974 EXPECT_TRUE(success);
1975 EXPECT_EQ(1u, Shell::windows().size());
1978 // Verify that when a new child frame is added, the proxies created for it in
1979 // other SiteInstances have correct sandbox flags and origin.
1981 // A A A
1982 // / / \ / \ .
1983 // B -> B A -> B A
1984 // \ .
1985 // B
1987 // The test checks sandbox flags and origin for the proxy added in step 2, by
1988 // checking whether the grandchild frame added in step 3 sees proper sandbox
1989 // flags and origin for its (remote) parent. This wasn't addressed when
1990 // https://crbug.com/423587 was fixed.
1991 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1992 ProxiesForNewChildFramesHaveCorrectReplicationState) {
1993 GURL main_url(
1994 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
1995 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1997 // It is safe to obtain the root frame tree node here, as it doesn't change.
1998 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1999 ->GetFrameTree()
2000 ->root();
2001 TestNavigationObserver observer(shell()->web_contents());
2003 EXPECT_EQ(
2004 " Site A ------------ proxies for B\n"
2005 " +--Site B ------- proxies for A\n"
2006 "Where A = http://127.0.0.1/\n"
2007 " B = http://baz.com/",
2008 DepictFrameTree(root));
2010 // In the root frame, add a new sandboxed local frame, which itself has a
2011 // child frame on baz.com. Wait for three RenderFrameHosts to be created:
2012 // the new sandboxed local frame, its child (while it's still local), and a
2013 // pending RFH when starting the cross-site navigation to baz.com.
2014 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 3);
2015 EXPECT_TRUE(
2016 ExecuteScript(root->current_frame_host(),
2017 "window.domAutomationController.send("
2018 " addFrame('/frame_tree/page_with_one_frame.html',"
2019 " 'allow-scripts allow-same-origin'))"));
2020 frame_observer.Wait();
2022 // Wait for the cross-site navigation to baz.com in the grandchild to finish.
2023 FrameTreeNode* bottom_child = root->child_at(1)->child_at(0);
2024 TestFrameNavigationObserver navigation_observer(bottom_child);
2025 navigation_observer.Wait();
2027 EXPECT_EQ(
2028 " Site A ------------ proxies for B\n"
2029 " |--Site B ------- proxies for A\n"
2030 " +--Site A ------- proxies for B\n"
2031 " +--Site B -- proxies for A\n"
2032 "Where A = http://127.0.0.1/\n"
2033 " B = http://baz.com/",
2034 DepictFrameTree(root));
2036 // Use location.ancestorOrigins to check that the grandchild on baz.com sees
2037 // correct origin for its parent.
2038 int ancestor_origins_length = 0;
2039 EXPECT_TRUE(ExecuteScriptAndExtractInt(
2040 bottom_child->current_frame_host(),
2041 "window.domAutomationController.send(location.ancestorOrigins.length);",
2042 &ancestor_origins_length));
2043 EXPECT_EQ(2, ancestor_origins_length);
2044 std::string parent_origin;
2045 EXPECT_TRUE(ExecuteScriptAndExtractString(
2046 bottom_child->current_frame_host(),
2047 "window.domAutomationController.send(location.ancestorOrigins[0]);",
2048 &parent_origin));
2049 EXPECT_EQ(main_url.GetOrigin().spec(), parent_origin + "/");
2051 // Check that the sandbox flags in the browser process are correct.
2052 // "allow-scripts" resets both WebSandboxFlags::Scripts and
2053 // WebSandboxFlags::AutomaticFeatures bits per blink::parseSandboxPolicy().
2054 blink::WebSandboxFlags expected_flags =
2055 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
2056 ~blink::WebSandboxFlags::AutomaticFeatures &
2057 ~blink::WebSandboxFlags::Origin;
2058 EXPECT_EQ(expected_flags,
2059 root->child_at(1)->current_replication_state().sandbox_flags);
2061 // The child of the sandboxed frame should've inherited sandbox flags, so it
2062 // should not be able to create popups.
2063 bool success = false;
2064 EXPECT_TRUE(
2065 ExecuteScriptAndExtractBool(bottom_child->current_frame_host(),
2066 "window.domAutomationController.send("
2067 "!window.open('data:text/html,dataurl'));",
2068 &success));
2069 EXPECT_TRUE(success);
2070 EXPECT_EQ(1u, Shell::windows().size());
2073 // Verify that a child frame can retrieve the name property set by its parent.
2074 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, WindowNameReplication) {
2075 GURL main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html"));
2076 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2078 // It is safe to obtain the root frame tree node here, as it doesn't change.
2079 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2080 ->GetFrameTree()
2081 ->root();
2083 TestNavigationObserver observer(shell()->web_contents());
2085 // Load cross-site page into iframe.
2086 GURL frame_url =
2087 embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html");
2088 NavigateFrameToURL(root->child_at(0), frame_url);
2089 EXPECT_TRUE(observer.last_navigation_succeeded());
2090 EXPECT_EQ(frame_url, observer.last_navigation_url());
2092 // Ensure that a new process is created for the subframe.
2093 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
2094 root->child_at(0)->current_frame_host()->GetSiteInstance());
2096 // Check that the window.name seen by the frame matches the name attribute
2097 // specified by its parent in the iframe tag.
2098 std::string result;
2099 EXPECT_TRUE(ExecuteScriptAndExtractString(
2100 root->child_at(0)->current_frame_host(),
2101 "window.domAutomationController.send(window.name);", &result));
2102 EXPECT_EQ("3-1-name", result);
2105 // Verify that dynamic updates to a frame's window.name propagate to the
2106 // frame's proxies, so that the latest frame names can be used in navigations.
2107 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicWindowName) {
2108 GURL main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html"));
2109 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2111 // It is safe to obtain the root frame tree node here, as it doesn't change.
2112 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2113 ->GetFrameTree()
2114 ->root();
2115 TestNavigationObserver observer(shell()->web_contents());
2117 // Load cross-site page into iframe.
2118 GURL frame_url =
2119 embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html");
2120 NavigateFrameToURL(root->child_at(0), frame_url);
2121 EXPECT_TRUE(observer.last_navigation_succeeded());
2122 EXPECT_EQ(frame_url, observer.last_navigation_url());
2124 // Browser process should know the child frame's original window.name
2125 // specified in the iframe element.
2126 EXPECT_EQ(root->child_at(0)->frame_name(), "3-1-name");
2128 // Update the child frame's window.name.
2129 EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
2130 "window.domAutomationController.send("
2131 "window.name = 'updated-name');"));
2133 // The change should propagate to the browser process.
2134 EXPECT_EQ(root->child_at(0)->frame_name(), "updated-name");
2136 // The proxy in the parent process should also receive the updated name.
2137 // Check that it can reference the child frame by its new name.
2138 bool success = false;
2139 EXPECT_TRUE(
2140 ExecuteScriptAndExtractBool(shell()->web_contents(),
2141 "window.domAutomationController.send("
2142 "frames['updated-name'] == frames[0]);",
2143 &success));
2144 EXPECT_TRUE(success);
2146 // Issue a renderer-initiated navigation from the root frame to the child
2147 // frame using the frame's name. Make sure correct frame is navigated.
2149 // TODO(alexmos): When blink::createWindow is refactored to handle
2150 // RemoteFrames, this should also be tested via window.open(url, frame_name)
2151 // and a more complicated frame hierarchy (https://crbug.com/463742)
2152 TestFrameNavigationObserver frame_observer(root->child_at(0));
2153 GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
2154 std::string script = base::StringPrintf(
2155 "window.domAutomationController.send("
2156 "frames['updated-name'].location.href = '%s');",
2157 foo_url.spec().c_str());
2158 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), script));
2159 frame_observer.Wait();
2160 EXPECT_EQ(foo_url, root->child_at(0)->current_url());
2163 // Verify that when a frame is navigated to a new origin, the origin update
2164 // propagates to the frame's proxies.
2165 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OriginUpdatesReachProxies) {
2166 GURL main_url(
2167 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
2168 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2170 // It is safe to obtain the root frame tree node here, as it doesn't change.
2171 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2172 ->GetFrameTree()
2173 ->root();
2174 TestNavigationObserver observer(shell()->web_contents());
2176 EXPECT_EQ(
2177 " Site A ------------ proxies for B\n"
2178 " |--Site B ------- proxies for A\n"
2179 " +--Site A ------- proxies for B\n"
2180 "Where A = http://127.0.0.1/\n"
2181 " B = http://bar.com/",
2182 DepictFrameTree(root));
2184 // Navigate second subframe to a baz.com. This should send an origin update
2185 // to the frame's proxy in the bar.com (first frame's) process.
2186 GURL frame_url = embedded_test_server()->GetURL("baz.com", "/title2.html");
2187 NavigateFrameToURL(root->child_at(1), frame_url);
2188 EXPECT_TRUE(observer.last_navigation_succeeded());
2189 EXPECT_EQ(frame_url, observer.last_navigation_url());
2191 // The first frame can't directly observe the second frame's origin with
2192 // JavaScript. Instead, try to navigate the second frame from the first
2193 // frame. This should fail with a console error message, which should
2194 // contain the second frame's updated origin (see blink::Frame::canNavigate).
2195 scoped_ptr<ConsoleObserverDelegate> console_delegate(
2196 new ConsoleObserverDelegate(
2197 shell()->web_contents(),
2198 "Unsafe JavaScript attempt to initiate navigation*"));
2199 shell()->web_contents()->SetDelegate(console_delegate.get());
2201 // frames[1] can't be used due to a bug where RemoteFrames are created out of
2202 // order (https://crbug.com/478792). Instead, target second frame by name.
2203 EXPECT_TRUE(ExecuteScript(
2204 root->child_at(0)->current_frame_host(),
2205 "window.domAutomationController.send("
2206 " parent.frames['frame2'].location.href = 'data:text/html,foo');"));
2207 console_delegate->Wait();
2209 std::string frame_origin =
2210 root->child_at(1)->current_replication_state().origin.string();
2211 EXPECT_EQ(frame_origin + "/", frame_url.GetOrigin().spec());
2212 EXPECT_TRUE(
2213 MatchPattern(console_delegate->message(), "*" + frame_origin + "*"))
2214 << "Error message does not contain the frame's latest origin ("
2215 << frame_origin << ")";
2218 // Ensure that navigating subframes in --site-per-process mode properly fires
2219 // the DidStopLoading event on WebContentsObserver.
2220 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteDidStopLoading) {
2221 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
2222 NavigateToURL(shell(), main_url);
2224 // It is safe to obtain the root frame tree node here, as it doesn't change.
2225 FrameTreeNode* root =
2226 static_cast<WebContentsImpl*>(shell()->web_contents())->
2227 GetFrameTree()->root();
2229 TestNavigationObserver observer(shell()->web_contents());
2231 // Load same-site page into iframe.
2232 FrameTreeNode* child = root->child_at(0);
2233 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
2234 NavigateFrameToURL(child, http_url);
2235 EXPECT_EQ(http_url, observer.last_navigation_url());
2236 EXPECT_TRUE(observer.last_navigation_succeeded());
2238 // Load cross-site page into iframe.
2239 TestNavigationObserver nav_observer(shell()->web_contents(), 1);
2240 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
2241 NavigationController::LoadURLParams params(url);
2242 params.transition_type = ui::PAGE_TRANSITION_LINK;
2243 params.frame_tree_node_id = child->frame_tree_node_id();
2244 child->navigator()->GetController()->LoadURLWithParams(params);
2245 nav_observer.Wait();
2247 // Verify that the navigation succeeded and the expected URL was loaded.
2248 EXPECT_TRUE(observer.last_navigation_succeeded());
2249 EXPECT_EQ(url, observer.last_navigation_url());
2252 // Ensure that the renderer does not crash when navigating a frame that has a
2253 // sibling RemoteFrame. See https://crbug.com/426953.
2254 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2255 NavigateWithSiblingRemoteFrame) {
2256 GURL main_url(
2257 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
2258 NavigateToURL(shell(), main_url);
2260 // It is safe to obtain the root frame tree node here, as it doesn't change.
2261 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2262 ->GetFrameTree()
2263 ->root();
2264 TestNavigationObserver observer(shell()->web_contents());
2266 // Make sure the first frame is out of process.
2267 ASSERT_EQ(2U, root->child_count());
2268 FrameTreeNode* node2 = root->child_at(0);
2269 EXPECT_NE(root->current_frame_host()->GetSiteInstance(),
2270 node2->current_frame_host()->GetSiteInstance());
2272 // Make sure the second frame is in the parent's process.
2273 FrameTreeNode* node3 = root->child_at(1);
2274 EXPECT_EQ(root->current_frame_host()->GetSiteInstance(),
2275 node3->current_frame_host()->GetSiteInstance());
2277 // Navigate the second iframe (node3) to a URL in its own process.
2278 GURL title_url = embedded_test_server()->GetURL("/title2.html");
2279 NavigateFrameToURL(node3, title_url);
2280 EXPECT_TRUE(observer.last_navigation_succeeded());
2281 EXPECT_EQ(title_url, observer.last_navigation_url());
2282 EXPECT_EQ(root->current_frame_host()->GetSiteInstance(),
2283 node3->current_frame_host()->GetSiteInstance());
2284 EXPECT_TRUE(node3->current_frame_host()->IsRenderFrameLive());
2287 // Verify that load events for iframe elements work when the child frame is
2288 // out-of-process. In such cases, the load event is forwarded from the child
2289 // frame to the parent frame via the browser process.
2290 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, LoadEventForwarding) {
2291 // Load a page with a cross-site frame. The parent page has an onload
2292 // handler in the iframe element that appends "LOADED" to the document title.
2294 GURL main_url(
2295 embedded_test_server()->GetURL("/frame_with_load_event.html"));
2296 base::string16 expected_title(base::UTF8ToUTF16("LOADED"));
2297 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
2298 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2299 EXPECT_EQ(title_watcher.WaitAndGetTitle(), expected_title);
2302 // It is safe to obtain the root frame tree node here, as it doesn't change.
2303 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2304 ->GetFrameTree()
2305 ->root();
2307 // Load another cross-site page into the iframe and check that the load event
2308 // is fired.
2310 GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
2311 base::string16 expected_title(base::UTF8ToUTF16("LOADEDLOADED"));
2312 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
2313 TestNavigationObserver observer(shell()->web_contents());
2314 NavigateFrameToURL(root->child_at(0), foo_url);
2315 EXPECT_TRUE(observer.last_navigation_succeeded());
2316 EXPECT_EQ(foo_url, observer.last_navigation_url());
2317 EXPECT_EQ(title_watcher.WaitAndGetTitle(), expected_title);
2321 // Check that postMessage can be routed between cross-site iframes.
2322 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SubframePostMessage) {
2323 GURL main_url(embedded_test_server()->GetURL(
2324 "/frame_tree/page_with_post_message_frames.html"));
2325 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2327 // It is safe to obtain the root frame tree node here, as it doesn't change.
2328 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2329 ->GetFrameTree()
2330 ->root();
2332 TestNavigationObserver observer(shell()->web_contents());
2333 ASSERT_EQ(2U, root->child_count());
2335 // Verify the frames start at correct URLs. First frame should be
2336 // same-site; second frame should be cross-site.
2337 GURL same_site_url(embedded_test_server()->GetURL("/post_message.html"));
2338 EXPECT_EQ(same_site_url, root->child_at(0)->current_url());
2339 GURL foo_url(embedded_test_server()->GetURL("foo.com",
2340 "/post_message.html"));
2341 EXPECT_EQ(foo_url, root->child_at(1)->current_url());
2342 EXPECT_NE(root->child_at(0)->current_frame_host()->GetSiteInstance(),
2343 root->child_at(1)->current_frame_host()->GetSiteInstance());
2345 // Send a message from first, same-site frame to second, cross-site frame.
2346 // Expect the second frame to reply back to the first frame.
2347 PostMessageAndWaitForReply(root->child_at(0),
2348 "postToSibling('subframe-msg','subframe2')",
2349 "\"done-subframe1\"");
2351 // Send a postMessage from second, cross-site frame to its parent. Expect
2352 // parent to send a reply to the frame.
2353 base::string16 expected_title(base::ASCIIToUTF16("subframe-msg"));
2354 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
2355 PostMessageAndWaitForReply(root->child_at(1), "postToParent('subframe-msg')",
2356 "\"done-subframe2\"");
2357 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
2359 // Verify the total number of received messages for each subframe. First
2360 // frame should have one message (reply from second frame), and second frame
2361 // should have two messages (message from first frame and reply from parent).
2362 int subframe1_received_messages = 0;
2363 int subframe2_received_messages = 0;
2364 EXPECT_TRUE(ExecuteScriptAndExtractInt(
2365 root->child_at(0)->current_frame_host(),
2366 "window.domAutomationController.send(window.receivedMessages);",
2367 &subframe1_received_messages));
2368 EXPECT_EQ(1, subframe1_received_messages);
2369 EXPECT_TRUE(ExecuteScriptAndExtractInt(
2370 root->child_at(1)->current_frame_host(),
2371 "window.domAutomationController.send(window.receivedMessages);",
2372 &subframe2_received_messages));
2373 EXPECT_EQ(2, subframe2_received_messages);
2376 // Check that parent.frames[num] references correct sibling frames when the
2377 // parent is remote. See https://crbug.com/478792.
2378 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, IndexedFrameAccess) {
2379 // Start on a page with three same-site subframes.
2380 GURL main_url(
2381 embedded_test_server()->GetURL("a.com", "/frame_tree/top.html"));
2382 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2384 // It is safe to obtain the root frame tree node here, as it doesn't change.
2385 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2386 ->GetFrameTree()
2387 ->root();
2388 ASSERT_EQ(3U, root->child_count());
2389 FrameTreeNode* child0 = root->child_at(0);
2390 FrameTreeNode* child1 = root->child_at(1);
2391 FrameTreeNode* child2 = root->child_at(2);
2393 // Send each of the frames to a different site. Each new renderer will first
2394 // create proxies for the parent and two sibling subframes and then create
2395 // and insert the new RenderFrame into the frame tree.
2396 GURL b_url(embedded_test_server()->GetURL("b.com", "/post_message.html"));
2397 GURL c_url(embedded_test_server()->GetURL("c.com", "/post_message.html"));
2398 GURL d_url(embedded_test_server()->GetURL("d.com", "/post_message.html"));
2399 NavigateFrameToURL(child0, b_url);
2400 // TODO(alexmos): The calls to WaitForRenderFrameReady can be removed once
2401 // TestFrameNavigationObserver is fixed to use DidFinishLoad.
2402 EXPECT_TRUE(WaitForRenderFrameReady(child0->current_frame_host()));
2403 NavigateFrameToURL(child1, c_url);
2404 EXPECT_TRUE(WaitForRenderFrameReady(child1->current_frame_host()));
2405 NavigateFrameToURL(child2, d_url);
2406 EXPECT_TRUE(WaitForRenderFrameReady(child2->current_frame_host()));
2408 EXPECT_EQ(
2409 " Site A ------------ proxies for B C D\n"
2410 " |--Site B ------- proxies for A C D\n"
2411 " |--Site C ------- proxies for A B D\n"
2412 " +--Site D ------- proxies for A B C\n"
2413 "Where A = http://a.com/\n"
2414 " B = http://b.com/\n"
2415 " C = http://c.com/\n"
2416 " D = http://d.com/",
2417 DepictFrameTree(root));
2419 // Check that each subframe sees itself at correct index in parent.frames.
2420 bool success = false;
2421 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2422 child0->current_frame_host(),
2423 "window.domAutomationController.send(window === parent.frames[0]);",
2424 &success));
2425 EXPECT_TRUE(success);
2427 success = false;
2428 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2429 child1->current_frame_host(),
2430 "window.domAutomationController.send(window === parent.frames[1]);",
2431 &success));
2432 EXPECT_TRUE(success);
2434 success = false;
2435 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2436 child2->current_frame_host(),
2437 "window.domAutomationController.send(window === parent.frames[2]);",
2438 &success));
2439 EXPECT_TRUE(success);
2441 // Send a postMessage from B to parent.frames[1], which should go to C, and
2442 // wait for reply.
2443 PostMessageAndWaitForReply(child0, "postToSibling('subframe-msg', 1)",
2444 "\"done-1-1-name\"");
2446 // Send a postMessage from C to parent.frames[2], which should go to D, and
2447 // wait for reply.
2448 PostMessageAndWaitForReply(child1, "postToSibling('subframe-msg', 2)",
2449 "\"done-1-2-name\"");
2451 // Verify the total number of received messages for each subframe.
2452 int child0_received_messages = 0;
2453 EXPECT_TRUE(ExecuteScriptAndExtractInt(
2454 child0->current_frame_host(),
2455 "window.domAutomationController.send(window.receivedMessages);",
2456 &child0_received_messages));
2457 EXPECT_EQ(1, child0_received_messages);
2459 int child1_received_messages = 0;
2460 EXPECT_TRUE(ExecuteScriptAndExtractInt(
2461 child1->current_frame_host(),
2462 "window.domAutomationController.send(window.receivedMessages);",
2463 &child1_received_messages));
2464 EXPECT_EQ(2, child1_received_messages);
2466 int child2_received_messages = 0;
2467 EXPECT_TRUE(ExecuteScriptAndExtractInt(
2468 child2->current_frame_host(),
2469 "window.domAutomationController.send(window.receivedMessages);",
2470 &child2_received_messages));
2471 EXPECT_EQ(1, child2_received_messages);
2474 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, RFPHDestruction) {
2475 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
2476 NavigateToURL(shell(), main_url);
2478 // It is safe to obtain the root frame tree node here, as it doesn't change.
2479 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2480 ->GetFrameTree()
2481 ->root();
2483 TestNavigationObserver observer(shell()->web_contents());
2485 // Load cross-site page into iframe.
2486 FrameTreeNode* child = root->child_at(0);
2487 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
2488 NavigateFrameToURL(root->child_at(0), url);
2489 EXPECT_TRUE(observer.last_navigation_succeeded());
2490 EXPECT_EQ(url, observer.last_navigation_url());
2491 EXPECT_EQ(
2492 " Site A ------------ proxies for B\n"
2493 " |--Site B ------- proxies for A\n"
2494 " +--Site A ------- proxies for B\n"
2495 " |--Site A -- proxies for B\n"
2496 " +--Site A -- proxies for B\n"
2497 " +--Site A -- proxies for B\n"
2498 "Where A = http://127.0.0.1/\n"
2499 " B = http://foo.com/",
2500 DepictFrameTree(root));
2502 // Load another cross-site page.
2503 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
2504 NavigateIframeToURL(shell()->web_contents(), "test", url);
2505 EXPECT_TRUE(observer.last_navigation_succeeded());
2506 EXPECT_EQ(url, observer.last_navigation_url());
2507 EXPECT_EQ(
2508 " Site A ------------ proxies for C\n"
2509 " |--Site C ------- proxies for A\n"
2510 " +--Site A ------- proxies for C\n"
2511 " |--Site A -- proxies for C\n"
2512 " +--Site A -- proxies for C\n"
2513 " +--Site A -- proxies for C\n"
2514 "Where A = http://127.0.0.1/\n"
2515 " C = http://bar.com/",
2516 DepictFrameTree(root));
2518 // Navigate back to the parent's origin.
2519 url = embedded_test_server()->GetURL("/title1.html");
2520 NavigateFrameToURL(child, url);
2521 EXPECT_EQ(url, observer.last_navigation_url());
2522 EXPECT_TRUE(observer.last_navigation_succeeded());
2523 EXPECT_EQ(
2524 " Site A\n"
2525 " |--Site A\n"
2526 " +--Site A\n"
2527 " |--Site A\n"
2528 " +--Site A\n"
2529 " +--Site A\n"
2530 "Where A = http://127.0.0.1/",
2531 DepictFrameTree(root));
2534 } // namespace content