Distiller feedback always in front of body element
[chromium-blink-merge.git] / content / browser / site_per_process_browsertest.cc
blob12888a1f3ac67e11ce702be6bc2dc3ca16c4f8d7
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/strings/stringprintf.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "content/browser/frame_host/cross_process_frame_connector.h"
14 #include "content/browser/frame_host/frame_tree.h"
15 #include "content/browser/frame_host/navigator.h"
16 #include "content/browser/frame_host/render_frame_proxy_host.h"
17 #include "content/browser/frame_host/render_widget_host_view_child_frame.h"
18 #include "content/browser/renderer_host/render_view_host_impl.h"
19 #include "content/browser/web_contents/web_contents_impl.h"
20 #include "content/common/frame_messages.h"
21 #include "content/public/browser/notification_observer.h"
22 #include "content/public/browser/notification_service.h"
23 #include "content/public/browser/notification_types.h"
24 #include "content/public/common/content_switches.h"
25 #include "content/public/test/browser_test_utils.h"
26 #include "content/public/test/content_browser_test_utils.h"
27 #include "content/public/test/test_navigation_observer.h"
28 #include "content/public/test/test_utils.h"
29 #include "content/shell/browser/shell.h"
30 #include "content/test/content_browser_test_utils_internal.h"
31 #include "content/test/test_frame_navigation_observer.h"
32 #include "ipc/ipc_security_test_util.h"
33 #include "net/dns/mock_host_resolver.h"
34 #include "net/test/embedded_test_server/embedded_test_server.h"
35 #include "third_party/WebKit/public/web/WebSandboxFlags.h"
37 namespace content {
39 namespace {
41 // Helper function to send a postMessage and wait for a reply message. The
42 // |post_message_script| is executed on the |sender_ftn| frame, and the sender
43 // frame is expected to post |reply_status| from the DOMAutomationController
44 // when it receives a reply.
45 void PostMessageAndWaitForReply(FrameTreeNode* sender_ftn,
46 const std::string& post_message_script,
47 const std::string& reply_status) {
48 bool success = false;
49 EXPECT_TRUE(ExecuteScriptAndExtractBool(
50 sender_ftn->current_frame_host(),
51 "window.domAutomationController.send(" + post_message_script + ");",
52 &success));
53 EXPECT_TRUE(success);
55 content::DOMMessageQueue msg_queue;
56 std::string status;
57 while (msg_queue.WaitForMessage(&status)) {
58 if (status == reply_status)
59 break;
63 } // anonymous namespace
65 class RedirectNotificationObserver : public NotificationObserver {
66 public:
67 // Register to listen for notifications of the given type from either a
68 // specific source, or from all sources if |source| is
69 // NotificationService::AllSources().
70 RedirectNotificationObserver(int notification_type,
71 const NotificationSource& source);
72 ~RedirectNotificationObserver() override;
74 // Wait until the specified notification occurs. If the notification was
75 // emitted between the construction of this object and this call then it
76 // returns immediately.
77 void Wait();
79 // Returns NotificationService::AllSources() if we haven't observed a
80 // notification yet.
81 const NotificationSource& source() const {
82 return source_;
85 const NotificationDetails& details() const {
86 return details_;
89 // NotificationObserver:
90 void Observe(int type,
91 const NotificationSource& source,
92 const NotificationDetails& details) override;
94 private:
95 bool seen_;
96 bool seen_twice_;
97 bool running_;
98 NotificationRegistrar registrar_;
100 NotificationSource source_;
101 NotificationDetails details_;
102 scoped_refptr<MessageLoopRunner> message_loop_runner_;
104 DISALLOW_COPY_AND_ASSIGN(RedirectNotificationObserver);
107 RedirectNotificationObserver::RedirectNotificationObserver(
108 int notification_type,
109 const NotificationSource& source)
110 : seen_(false),
111 running_(false),
112 source_(NotificationService::AllSources()) {
113 registrar_.Add(this, notification_type, source);
116 RedirectNotificationObserver::~RedirectNotificationObserver() {}
118 void RedirectNotificationObserver::Wait() {
119 if (seen_ && seen_twice_)
120 return;
122 running_ = true;
123 message_loop_runner_ = new MessageLoopRunner;
124 message_loop_runner_->Run();
125 EXPECT_TRUE(seen_);
128 void RedirectNotificationObserver::Observe(
129 int type,
130 const NotificationSource& source,
131 const NotificationDetails& details) {
132 source_ = source;
133 details_ = details;
134 seen_twice_ = seen_;
135 seen_ = true;
136 if (!running_)
137 return;
139 message_loop_runner_->Quit();
140 running_ = false;
143 // This observer keeps track of the number of created RenderFrameHosts. Tests
144 // can use this to ensure that a certain number of child frames has been
145 // created after navigating.
146 class RenderFrameHostCreatedObserver : public WebContentsObserver {
147 public:
148 RenderFrameHostCreatedObserver(WebContents* web_contents,
149 int expected_frame_count)
150 : WebContentsObserver(web_contents),
151 expected_frame_count_(expected_frame_count),
152 frames_created_(0),
153 message_loop_runner_(new MessageLoopRunner) {}
155 ~RenderFrameHostCreatedObserver() override;
157 // Runs a nested message loop and blocks until the expected number of
158 // RenderFrameHosts is created.
159 void Wait();
161 private:
162 // WebContentsObserver
163 void RenderFrameCreated(RenderFrameHost* render_frame_host) override;
165 // The number of RenderFrameHosts to wait for.
166 int expected_frame_count_;
168 // The number of RenderFrameHosts that have been created.
169 int frames_created_;
171 // The MessageLoopRunner used to spin the message loop.
172 scoped_refptr<MessageLoopRunner> message_loop_runner_;
174 DISALLOW_COPY_AND_ASSIGN(RenderFrameHostCreatedObserver);
177 RenderFrameHostCreatedObserver::~RenderFrameHostCreatedObserver() {
180 void RenderFrameHostCreatedObserver::Wait() {
181 message_loop_runner_->Run();
184 void RenderFrameHostCreatedObserver::RenderFrameCreated(
185 RenderFrameHost* render_frame_host) {
186 frames_created_++;
187 if (frames_created_ == expected_frame_count_) {
188 message_loop_runner_->Quit();
192 // A WebContentsDelegate that catches messages sent to the console.
193 class ConsoleObserverDelegate : public WebContentsDelegate {
194 public:
195 ConsoleObserverDelegate(WebContents* web_contents, const std::string& filter)
196 : web_contents_(web_contents),
197 filter_(filter),
198 message_(""),
199 message_loop_runner_(new MessageLoopRunner) {}
201 ~ConsoleObserverDelegate() override {}
203 bool AddMessageToConsole(WebContents* source,
204 int32 level,
205 const base::string16& message,
206 int32 line_no,
207 const base::string16& source_id) override;
209 std::string message() { return message_; }
211 void Wait();
213 private:
214 WebContents* web_contents_;
215 std::string filter_;
216 std::string message_;
218 // The MessageLoopRunner used to spin the message loop.
219 scoped_refptr<MessageLoopRunner> message_loop_runner_;
221 DISALLOW_COPY_AND_ASSIGN(ConsoleObserverDelegate);
224 void ConsoleObserverDelegate::Wait() {
225 message_loop_runner_->Run();
228 bool ConsoleObserverDelegate::AddMessageToConsole(
229 WebContents* source,
230 int32 level,
231 const base::string16& message,
232 int32 line_no,
233 const base::string16& source_id) {
234 DCHECK(source == web_contents_);
236 std::string ascii_message = base::UTF16ToASCII(message);
237 if (MatchPattern(ascii_message, filter_)) {
238 message_ = ascii_message;
239 message_loop_runner_->Quit();
241 return false;
245 // SitePerProcessBrowserTest
248 SitePerProcessBrowserTest::SitePerProcessBrowserTest() {
251 std::string SitePerProcessBrowserTest::DepictFrameTree(FrameTreeNode* node) {
252 return visualizer_.DepictFrameTree(node);
255 void SitePerProcessBrowserTest::StartFrameAtDataURL() {
256 std::string data_url_script =
257 "var iframes = document.getElementById('test');iframes.src="
258 "'data:text/html,dataurl';";
259 ASSERT_TRUE(ExecuteScript(shell()->web_contents(), data_url_script));
262 void SitePerProcessBrowserTest::SetUpCommandLine(
263 base::CommandLine* command_line) {
264 command_line->AppendSwitch(switches::kSitePerProcess);
267 void SitePerProcessBrowserTest::SetUpOnMainThread() {
268 host_resolver()->AddRule("*", "127.0.0.1");
269 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
270 SetupCrossSiteRedirector(embedded_test_server());
273 // Ensure that navigating subframes in --site-per-process mode works and the
274 // correct documents are committed.
275 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframe) {
276 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
277 NavigateToURL(shell(), main_url);
279 // It is safe to obtain the root frame tree node here, as it doesn't change.
280 FrameTreeNode* root =
281 static_cast<WebContentsImpl*>(shell()->web_contents())->
282 GetFrameTree()->root();
284 TestNavigationObserver observer(shell()->web_contents());
286 // Load same-site page into iframe.
287 FrameTreeNode* child = root->child_at(0);
288 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
289 NavigateFrameToURL(child, http_url);
290 EXPECT_EQ(http_url, observer.last_navigation_url());
291 EXPECT_TRUE(observer.last_navigation_succeeded());
293 // There should be only one RenderWidgetHost when there are no
294 // cross-process iframes.
295 std::set<RenderWidgetHostView*> views_set =
296 static_cast<WebContentsImpl*>(shell()->web_contents())
297 ->GetRenderWidgetHostViewsInTree();
298 EXPECT_EQ(1U, views_set.size());
301 EXPECT_EQ(
302 " Site A\n"
303 " |--Site A\n"
304 " +--Site A\n"
305 " |--Site A\n"
306 " +--Site A\n"
307 " +--Site A\n"
308 "Where A = http://127.0.0.1/",
309 DepictFrameTree(root));
311 // Load cross-site page into iframe.
312 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
313 NavigateFrameToURL(root->child_at(0), url);
314 // Verify that the navigation succeeded and the expected URL was loaded.
315 EXPECT_TRUE(observer.last_navigation_succeeded());
316 EXPECT_EQ(url, observer.last_navigation_url());
318 // Ensure that we have created a new process for the subframe.
319 ASSERT_EQ(2U, root->child_count());
320 SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
321 RenderViewHost* rvh = child->current_frame_host()->render_view_host();
322 RenderProcessHost* rph = child->current_frame_host()->GetProcess();
323 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh);
324 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
325 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), rph);
327 // There should be now two RenderWidgetHosts, one for each process
328 // rendering a frame.
329 std::set<RenderWidgetHostView*> views_set =
330 static_cast<WebContentsImpl*>(shell()->web_contents())
331 ->GetRenderWidgetHostViewsInTree();
332 EXPECT_EQ(2U, views_set.size());
334 RenderFrameProxyHost* proxy_to_parent =
335 child->render_manager()->GetProxyToParent();
336 EXPECT_TRUE(proxy_to_parent);
337 EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
338 // The out-of-process iframe should have its own RenderWidgetHost,
339 // independent of any RenderViewHost.
340 EXPECT_NE(
341 rvh->GetView(),
342 proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
343 EXPECT_TRUE(child->current_frame_host()->GetRenderWidgetHost());
345 EXPECT_EQ(
346 " Site A ------------ proxies for B\n"
347 " |--Site B ------- proxies for A\n"
348 " +--Site A ------- proxies for B\n"
349 " |--Site A -- proxies for B\n"
350 " +--Site A -- proxies for B\n"
351 " +--Site A -- proxies for B\n"
352 "Where A = http://127.0.0.1/\n"
353 " B = http://foo.com/",
354 DepictFrameTree(root));
356 // Load another cross-site page into the same iframe.
357 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
358 NavigateFrameToURL(root->child_at(0), url);
359 EXPECT_TRUE(observer.last_navigation_succeeded());
360 EXPECT_EQ(url, observer.last_navigation_url());
362 // Check again that a new process is created and is different from the
363 // top level one and the previous one.
364 ASSERT_EQ(2U, root->child_count());
365 child = root->child_at(0);
366 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(),
367 child->current_frame_host()->render_view_host());
368 EXPECT_NE(rvh, child->current_frame_host()->render_view_host());
369 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
370 child->current_frame_host()->GetSiteInstance());
371 EXPECT_NE(site_instance,
372 child->current_frame_host()->GetSiteInstance());
373 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(),
374 child->current_frame_host()->GetProcess());
375 EXPECT_NE(rph, child->current_frame_host()->GetProcess());
377 std::set<RenderWidgetHostView*> views_set =
378 static_cast<WebContentsImpl*>(shell()->web_contents())
379 ->GetRenderWidgetHostViewsInTree();
380 EXPECT_EQ(2U, views_set.size());
382 EXPECT_EQ(proxy_to_parent, child->render_manager()->GetProxyToParent());
383 EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
384 EXPECT_NE(
385 child->current_frame_host()->render_view_host()->GetView(),
386 proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
387 EXPECT_TRUE(child->current_frame_host()->GetRenderWidgetHost());
389 EXPECT_EQ(
390 " Site A ------------ proxies for C\n"
391 " |--Site C ------- proxies for A\n"
392 " +--Site A ------- proxies for C\n"
393 " |--Site A -- proxies for C\n"
394 " +--Site A -- proxies for C\n"
395 " +--Site A -- proxies for C\n"
396 "Where A = http://127.0.0.1/\n"
397 " C = http://bar.com/",
398 DepictFrameTree(root));
401 // Tests OOPIF rendering by checking that the RWH of the iframe generates
402 // OnSwapCompositorFrame message.
403 #if defined(OS_ANDROID)
404 // http://crbug.com/471850
405 #define MAYBE_CompositorFrameSwapped DISABLED_CompositorFrameSwapped
406 #else
407 #define MAYBE_CompositorFrameSwapped CompositorFrameSwapped
408 #endif
409 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
410 MAYBE_CompositorFrameSwapped) {
411 GURL main_url(
412 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
413 NavigateToURL(shell(), main_url);
415 // It is safe to obtain the root frame tree node here, as it doesn't change.
416 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
417 ->GetFrameTree()
418 ->root();
419 ASSERT_EQ(1U, root->child_count());
421 FrameTreeNode* child_node = root->child_at(0);
422 GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
423 EXPECT_EQ(site_url, child_node->current_url());
424 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
425 child_node->current_frame_host()->GetSiteInstance());
426 RenderWidgetHostViewBase* rwhv_base = static_cast<RenderWidgetHostViewBase*>(
427 child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
429 // Wait for OnSwapCompositorFrame message.
430 while (rwhv_base->RendererFrameNumber() <= 0) {
431 // TODO(lazyboy): Find a better way to avoid sleeping like this. See
432 // http://crbug.com/405282 for details.
433 base::RunLoop run_loop;
434 base::MessageLoop::current()->PostDelayedTask(
435 FROM_HERE, run_loop.QuitClosure(),
436 base::TimeDelta::FromMilliseconds(10));
437 run_loop.Run();
441 // Ensure that OOPIFs are deleted after navigating to a new main frame.
442 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CleanupCrossSiteIframe) {
443 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
444 NavigateToURL(shell(), main_url);
446 // It is safe to obtain the root frame tree node here, as it doesn't change.
447 FrameTreeNode* root =
448 static_cast<WebContentsImpl*>(shell()->web_contents())->
449 GetFrameTree()->root();
451 TestNavigationObserver observer(shell()->web_contents());
453 // Load a cross-site page into both iframes.
454 GURL foo_url = embedded_test_server()->GetURL("foo.com", "/title2.html");
455 NavigateFrameToURL(root->child_at(0), foo_url);
456 EXPECT_TRUE(observer.last_navigation_succeeded());
457 EXPECT_EQ(foo_url, observer.last_navigation_url());
458 NavigateFrameToURL(root->child_at(1), foo_url);
459 EXPECT_TRUE(observer.last_navigation_succeeded());
460 EXPECT_EQ(foo_url, observer.last_navigation_url());
462 // Ensure that we have created a new process for the subframes.
463 EXPECT_EQ(
464 " Site A ------------ proxies for B\n"
465 " |--Site B ------- proxies for A\n"
466 " +--Site B ------- proxies for A\n"
467 "Where A = http://127.0.0.1/\n"
468 " B = http://foo.com/",
469 DepictFrameTree(root));
471 int subframe_process_id = root->child_at(0)
472 ->current_frame_host()
473 ->GetSiteInstance()
474 ->GetProcess()
475 ->GetID();
476 int subframe_rvh_id = root->child_at(0)
477 ->current_frame_host()
478 ->render_view_host()
479 ->GetRoutingID();
480 EXPECT_TRUE(RenderViewHost::FromID(subframe_process_id, subframe_rvh_id));
482 // Use Javascript in the parent to remove one of the frames and ensure that
483 // the subframe goes away.
484 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
485 "document.body.removeChild("
486 "document.querySelectorAll('iframe')[0])"));
487 ASSERT_EQ(1U, root->child_count());
489 // Load a new same-site page in the top-level frame and ensure the other
490 // subframe goes away.
491 GURL new_url(embedded_test_server()->GetURL("/title1.html"));
492 NavigateToURL(shell(), new_url);
493 ASSERT_EQ(0U, root->child_count());
495 // Ensure the RVH for the subframe gets cleaned up when the frame goes away.
496 EXPECT_FALSE(RenderViewHost::FromID(subframe_process_id, subframe_rvh_id));
499 // Ensure that root frames cannot be detached.
500 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, RestrictFrameDetach) {
501 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
502 NavigateToURL(shell(), main_url);
504 // It is safe to obtain the root frame tree node here, as it doesn't change.
505 FrameTreeNode* root =
506 static_cast<WebContentsImpl*>(shell()->web_contents())->
507 GetFrameTree()->root();
509 TestNavigationObserver observer(shell()->web_contents());
511 // Load cross-site pages into both iframes.
512 GURL foo_url = embedded_test_server()->GetURL("foo.com", "/title2.html");
513 NavigateFrameToURL(root->child_at(0), foo_url);
514 EXPECT_TRUE(observer.last_navigation_succeeded());
515 EXPECT_EQ(foo_url, observer.last_navigation_url());
516 GURL bar_url = embedded_test_server()->GetURL("bar.com", "/title2.html");
517 NavigateFrameToURL(root->child_at(1), bar_url);
518 EXPECT_TRUE(observer.last_navigation_succeeded());
519 EXPECT_EQ(bar_url, observer.last_navigation_url());
521 // Ensure that we have created new processes for the subframes.
522 ASSERT_EQ(2U, root->child_count());
523 FrameTreeNode* foo_child = root->child_at(0);
524 SiteInstance* foo_site_instance =
525 foo_child->current_frame_host()->GetSiteInstance();
526 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), foo_site_instance);
527 FrameTreeNode* bar_child = root->child_at(1);
528 SiteInstance* bar_site_instance =
529 bar_child->current_frame_host()->GetSiteInstance();
530 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), bar_site_instance);
532 EXPECT_EQ(
533 " Site A ------------ proxies for B C\n"
534 " |--Site B ------- proxies for A C\n"
535 " +--Site C ------- proxies for A B\n"
536 "Where A = http://127.0.0.1/\n"
537 " B = http://foo.com/\n"
538 " C = http://bar.com/",
539 DepictFrameTree(root));
541 // Simulate an attempt to detach the root frame from foo_site_instance. This
542 // should kill foo_site_instance's process.
543 RenderFrameProxyHost* foo_mainframe_rfph =
544 root->render_manager()->GetRenderFrameProxyHost(foo_site_instance);
545 content::RenderProcessHostWatcher foo_terminated(
546 foo_mainframe_rfph->GetProcess(),
547 content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
548 FrameHostMsg_Detach evil_msg2(foo_mainframe_rfph->GetRoutingID());
549 IPC::IpcSecurityTestUtil::PwnMessageReceived(
550 foo_mainframe_rfph->GetProcess()->GetChannel(), evil_msg2);
551 foo_terminated.Wait();
553 EXPECT_EQ(
554 " Site A ------------ proxies for B C\n"
555 " |--Site B ------- proxies for A C\n"
556 " +--Site C ------- proxies for A B\n"
557 "Where A = http://127.0.0.1/\n"
558 " B = http://foo.com/ (no process)\n"
559 " C = http://bar.com/",
560 DepictFrameTree(root));
563 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
564 NavigateRemoteFrame) {
565 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
566 NavigateToURL(shell(), main_url);
568 // It is safe to obtain the root frame tree node here, as it doesn't change.
569 FrameTreeNode* root =
570 static_cast<WebContentsImpl*>(shell()->web_contents())->
571 GetFrameTree()->root();
573 TestNavigationObserver observer(shell()->web_contents());
575 // Load same-site page into iframe.
576 FrameTreeNode* child = root->child_at(0);
577 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
578 NavigateFrameToURL(child, http_url);
579 EXPECT_EQ(http_url, observer.last_navigation_url());
580 EXPECT_TRUE(observer.last_navigation_succeeded());
582 // Load cross-site page into iframe.
583 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
584 NavigateFrameToURL(root->child_at(0), url);
585 EXPECT_TRUE(observer.last_navigation_succeeded());
586 EXPECT_EQ(url, observer.last_navigation_url());
588 // Ensure that we have created a new process for the subframe.
589 ASSERT_EQ(2U, root->child_count());
590 SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
591 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
593 // Emulate the main frame changing the src of the iframe such that it
594 // navigates cross-site.
595 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
596 NavigateIframeToURL(shell()->web_contents(), "test", url);
597 EXPECT_TRUE(observer.last_navigation_succeeded());
598 EXPECT_EQ(url, observer.last_navigation_url());
600 // Check again that a new process is created and is different from the
601 // top level one and the previous one.
602 ASSERT_EQ(2U, root->child_count());
603 child = root->child_at(0);
604 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
605 child->current_frame_host()->GetSiteInstance());
606 EXPECT_NE(site_instance,
607 child->current_frame_host()->GetSiteInstance());
609 // Navigate back to the parent's origin and ensure we return to the
610 // parent's process.
611 NavigateFrameToURL(child, http_url);
612 EXPECT_EQ(http_url, observer.last_navigation_url());
613 EXPECT_TRUE(observer.last_navigation_succeeded());
614 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
615 child->current_frame_host()->GetSiteInstance());
618 #if defined(OS_WIN)
619 // http://crbug.com/465722
620 #define MAYBE_NavigateRemoteFrameToBlankAndDataURLs \
621 DISABLED_NavigateRemoteFrameToBlankAndDataURLs
622 #else
623 #define MAYBE_NavigateRemoteFrameToBlankAndDataURLs \
624 NavigateRemoteFrameToBlankAndDataURLs
625 #endif
627 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
628 MAYBE_NavigateRemoteFrameToBlankAndDataURLs) {
629 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
630 NavigateToURL(shell(), main_url);
632 // It is safe to obtain the root frame tree node here, as it doesn't change.
633 FrameTreeNode* root =
634 static_cast<WebContentsImpl*>(shell()->web_contents())->
635 GetFrameTree()->root();
637 TestNavigationObserver observer(shell()->web_contents());
639 // Load same-site page into iframe.
640 FrameTreeNode* child = root->child_at(0);
641 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
642 NavigateFrameToURL(child, http_url);
643 EXPECT_EQ(http_url, observer.last_navigation_url());
644 EXPECT_TRUE(observer.last_navigation_succeeded());
646 // Load cross-site page into iframe.
647 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
648 NavigateFrameToURL(root->child_at(0), url);
649 EXPECT_TRUE(observer.last_navigation_succeeded());
650 EXPECT_EQ(url, observer.last_navigation_url());
651 ASSERT_EQ(2U, root->child_count());
652 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
653 root->child_at(0)->current_frame_host()->GetSiteInstance());
655 // Navigate iframe to a data URL. The navigation happens from a script in the
656 // parent frame, so the data URL should be committed in the same SiteInstance
657 // as the parent frame.
658 GURL data_url("data:text/html,dataurl");
659 NavigateIframeToURL(shell()->web_contents(), "test", data_url);
660 EXPECT_TRUE(observer.last_navigation_succeeded());
661 EXPECT_EQ(data_url, observer.last_navigation_url());
663 // Ensure that we have navigated using the top level process.
664 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
665 root->child_at(0)->current_frame_host()->GetSiteInstance());
667 // Load cross-site page into iframe.
668 url = embedded_test_server()->GetURL("bar.com", "/title2.html");
669 NavigateFrameToURL(root->child_at(0), url);
670 EXPECT_TRUE(observer.last_navigation_succeeded());
671 EXPECT_EQ(url, observer.last_navigation_url());
672 ASSERT_EQ(2U, root->child_count());
673 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
674 root->child_at(0)->current_frame_host()->GetSiteInstance());
676 // Navigate iframe to about:blank. The navigation happens from a script in the
677 // parent frame, so it should be committed in the same SiteInstance as the
678 // parent frame.
679 GURL about_blank_url("about:blank");
680 NavigateIframeToURL(shell()->web_contents(), "test", about_blank_url);
681 EXPECT_TRUE(observer.last_navigation_succeeded());
682 EXPECT_EQ(about_blank_url, observer.last_navigation_url());
684 // Ensure that we have navigated using the top level process.
685 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
686 root->child_at(0)->current_frame_host()->GetSiteInstance());
689 // This test checks that killing a renderer process of a remote frame
690 // and then navigating some other frame to the same SiteInstance of the killed
691 // process works properly.
692 // This can be illustrated as follows,
693 // where 1/2/3 are FrameTreeNode-s and A/B are processes and B* is the killed
694 // B process:
696 // 1 A A A
697 // / \ -> / \ -> Kill B -> / \ -> Navigate 3 to B -> / \ .
698 // 2 3 B A B* A B* B
700 // Initially, node1.proxy_hosts_ = {B}
701 // After we kill B, we make sure B stays in node1.proxy_hosts_, then we navigate
702 // 3 to B and we expect that to complete normally.
703 // See http://crbug.com/432107.
705 // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
706 // site B and stays in not rendered state.
707 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
708 NavigateRemoteFrameToKilledProcess) {
709 GURL main_url(embedded_test_server()->GetURL(
710 "/frame_tree/page_with_two_frames.html"));
711 NavigateToURL(shell(), main_url);
713 // It is safe to obtain the root frame tree node here, as it doesn't change.
714 FrameTreeNode* root =
715 static_cast<WebContentsImpl*>(shell()->web_contents())->
716 GetFrameTree()->root();
718 TestNavigationObserver observer(shell()->web_contents());
719 ASSERT_EQ(2U, root->child_count());
721 // Make sure node2 points to the correct cross-site page.
722 GURL site_b_url = embedded_test_server()->GetURL("bar.com", "/title1.html");
723 FrameTreeNode* node2 = root->child_at(0);
724 EXPECT_EQ(site_b_url, node2->current_url());
726 // Kill that cross-site renderer.
727 RenderProcessHost* child_process =
728 node2->current_frame_host()->GetProcess();
729 RenderProcessHostWatcher crash_observer(
730 child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
731 child_process->Shutdown(0, false);
732 crash_observer.Wait();
734 // Now navigate the second iframe (node3) to the same site as the node2.
735 FrameTreeNode* node3 = root->child_at(1);
736 NavigateFrameToURL(node3, site_b_url);
737 EXPECT_TRUE(observer.last_navigation_succeeded());
738 EXPECT_EQ(site_b_url, observer.last_navigation_url());
741 // This test is similar to
742 // SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcess with
743 // addition that node2 also has a cross-origin frame to site C.
745 // 1 A A A
746 // / \ / \ / \ / \ .
747 // 2 3 -> B A -> Kill B -> B* A -> Navigate 3 -> B* B
748 // / /
749 // 4 C
751 // Initially, node1.proxy_hosts_ = {B, C}
752 // After we kill B, we make sure B stays in node1.proxy_hosts_, but
753 // C gets cleared from node1.proxy_hosts_.
755 // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
756 // site B and stays in not rendered state.
757 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
758 NavigateRemoteFrameToKilledProcessWithSubtree) {
759 GURL main_url(embedded_test_server()->GetURL(
760 "a.com", "/frame_tree/page_with_two_frames_nested.html"));
761 NavigateToURL(shell(), main_url);
763 // It is safe to obtain the root frame tree node here, as it doesn't change.
764 FrameTreeNode* root =
765 static_cast<WebContentsImpl*>(shell()->web_contents())->
766 GetFrameTree()->root();
767 TestNavigationObserver observer(shell()->web_contents());
769 ASSERT_EQ(2U, root->child_count());
771 GURL site_b_url(
772 embedded_test_server()->GetURL(
773 "bar.com", "/frame_tree/page_with_one_frame.html"));
774 // We can't use a TestNavigationObserver to verify the URL here,
775 // since the frame has children that may have clobbered it in the observer.
776 EXPECT_EQ(site_b_url, root->child_at(0)->current_url());
778 // Ensure that a new process is created for node2.
779 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
780 root->child_at(0)->current_frame_host()->GetSiteInstance());
781 // Ensure that a new process is *not* created for node3.
782 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
783 root->child_at(1)->current_frame_host()->GetSiteInstance());
785 ASSERT_EQ(1U, root->child_at(0)->child_count());
787 // Make sure node4 points to the correct cross-site page.
788 FrameTreeNode* node4 = root->child_at(0)->child_at(0);
789 GURL site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
790 EXPECT_EQ(site_c_url, node4->current_url());
792 // |site_instance_c| is expected to go away once we kill |child_process_b|
793 // below, so create a local scope so we can extend the lifetime of
794 // |site_instance_c| with a refptr.
796 // Initially each frame has proxies for the other sites.
797 EXPECT_EQ(
798 " Site A ------------ proxies for B C\n"
799 " |--Site B ------- proxies for A C\n"
800 " | +--Site C -- proxies for A B\n"
801 " +--Site A ------- proxies for B C\n"
802 "Where A = http://a.com/\n"
803 " B = http://bar.com/\n"
804 " C = http://baz.com/",
805 DepictFrameTree(root));
807 // Kill the render process for Site B.
808 RenderProcessHost* child_process_b =
809 root->child_at(0)->current_frame_host()->GetProcess();
810 RenderProcessHostWatcher crash_observer(
811 child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
812 child_process_b->Shutdown(0, false);
813 crash_observer.Wait();
815 // The Site C frame (a child of the crashed Site B frame) should go away,
816 // and there should be no remaining proxies for site C anywhere.
817 EXPECT_EQ(
818 " Site A ------------ proxies for B\n"
819 " |--Site B ------- proxies for A\n"
820 " +--Site A ------- proxies for B\n"
821 "Where A = http://a.com/\n"
822 " B = http://bar.com/ (no process)",
823 DepictFrameTree(root));
826 // Now navigate the second iframe (node3) to Site B also.
827 FrameTreeNode* node3 = root->child_at(1);
828 GURL url = embedded_test_server()->GetURL("bar.com", "/title1.html");
829 NavigateFrameToURL(node3, url);
830 EXPECT_TRUE(observer.last_navigation_succeeded());
831 EXPECT_EQ(url, observer.last_navigation_url());
833 EXPECT_EQ(
834 " Site A ------------ proxies for B\n"
835 " |--Site B ------- proxies for A\n"
836 " +--Site B ------- proxies for A\n"
837 "Where A = http://a.com/\n"
838 " B = http://bar.com/",
839 DepictFrameTree(root));
842 // Verify that killing a cross-site frame's process B and then navigating a
843 // frame to B correctly recreates all proxies in B.
845 // 1 A A A
846 // / | \ / | \ / | \ / | \ .
847 // 2 3 4 -> B A A -> Kill B -> B* A A -> B* B A
849 // After the last step, the test sends a postMessage from node 3 to node 4,
850 // verifying that a proxy for node 4 has been recreated in process B. This
851 // verifies the fix for https://crbug.com/478892.
852 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
853 NavigatingToKilledProcessRestoresAllProxies) {
854 // Navigate to a page with three frames: one cross-site and two same-site.
855 GURL main_url(embedded_test_server()->GetURL(
856 "a.com", "/frame_tree/page_with_three_frames.html"));
857 NavigateToURL(shell(), main_url);
859 // It is safe to obtain the root frame tree node here, as it doesn't change.
860 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
861 ->GetFrameTree()
862 ->root();
863 TestNavigationObserver observer(shell()->web_contents());
865 EXPECT_EQ(
866 " Site A ------------ proxies for B\n"
867 " |--Site B ------- proxies for A\n"
868 " |--Site A ------- proxies for B\n"
869 " +--Site A ------- proxies for B\n"
870 "Where A = http://a.com/\n"
871 " B = http://b.com/",
872 DepictFrameTree(root));
874 // Kill the first subframe's b.com renderer.
875 RenderProcessHost* child_process =
876 root->child_at(0)->current_frame_host()->GetProcess();
877 RenderProcessHostWatcher crash_observer(
878 child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
879 child_process->Shutdown(0, false);
880 crash_observer.Wait();
882 // Navigate the second subframe to b.com to recreate the b.com process.
883 GURL b_url = embedded_test_server()->GetURL("b.com", "/post_message.html");
884 NavigateFrameToURL(root->child_at(1), b_url);
885 // TODO(alexmos): This can be removed once TestFrameNavigationObserver is
886 // fixed to use DidFinishLoad.
887 EXPECT_TRUE(
888 WaitForRenderFrameReady(root->child_at(1)->current_frame_host()));
889 EXPECT_TRUE(observer.last_navigation_succeeded());
890 EXPECT_EQ(b_url, observer.last_navigation_url());
891 EXPECT_TRUE(root->child_at(1)->current_frame_host()->IsRenderFrameLive());
893 EXPECT_EQ(
894 " Site A ------------ proxies for B\n"
895 " |--Site B ------- proxies for A\n"
896 " |--Site B ------- proxies for A\n"
897 " +--Site A ------- proxies for B\n"
898 "Where A = http://a.com/\n"
899 " B = http://b.com/",
900 DepictFrameTree(root));
902 // Check that third subframe's proxy is available in the b.com process by
903 // sending it a postMessage from second subframe, and waiting for a reply.
904 PostMessageAndWaitForReply(root->child_at(1),
905 "postToSibling('subframe-msg','frame3')",
906 "\"done-frame2\"");
909 // Verify that proxy creation doesn't recreate a crashed process if no frame
910 // will be created in it.
912 // 1 A A A
913 // / | \ / | \ / | \ / | \ .
914 // 2 3 4 -> B A A -> Kill B -> B* A A -> B* A A
915 // \ .
916 // A
918 // The test kills process B (node 2), creates a child frame of node 4 in
919 // process A, and then checks that process B isn't resurrected to create a
920 // proxy for the new child frame. See https://crbug.com/476846.
921 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
922 CreateChildFrameAfterKillingProcess) {
923 // Navigate to a page with three frames: one cross-site and two same-site.
924 GURL main_url(embedded_test_server()->GetURL(
925 "a.com", "/frame_tree/page_with_three_frames.html"));
926 EXPECT_TRUE(NavigateToURL(shell(), main_url));
928 // It is safe to obtain the root frame tree node here, as it doesn't change.
929 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
930 ->GetFrameTree()
931 ->root();
933 EXPECT_EQ(
934 " Site A ------------ proxies for B\n"
935 " |--Site B ------- proxies for A\n"
936 " |--Site A ------- proxies for B\n"
937 " +--Site A ------- proxies for B\n"
938 "Where A = http://a.com/\n"
939 " B = http://b.com/",
940 DepictFrameTree(root));
941 SiteInstance* b_site_instance =
942 root->child_at(0)->current_frame_host()->GetSiteInstance();
944 // Kill the first subframe's renderer (B).
945 RenderProcessHost* child_process =
946 root->child_at(0)->current_frame_host()->GetProcess();
947 RenderProcessHostWatcher crash_observer(
948 child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
949 child_process->Shutdown(0, false);
950 crash_observer.Wait();
952 // Add a new child frame to the third subframe.
953 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 1);
954 EXPECT_TRUE(ExecuteScript(
955 root->child_at(2)->current_frame_host(),
956 "document.body.appendChild(document.createElement('iframe'));"));
957 frame_observer.Wait();
959 // The new frame should have a RenderFrameProxyHost for B, but it should not
960 // be alive, and B should still not have a process (verified by last line of
961 // expected DepictFrameTree output).
962 EXPECT_EQ(
963 " Site A ------------ proxies for B\n"
964 " |--Site B ------- proxies for A\n"
965 " |--Site A ------- proxies for B\n"
966 " +--Site A ------- proxies for B\n"
967 " +--Site A -- proxies for B\n"
968 "Where A = http://a.com/\n"
969 " B = http://b.com/ (no process)",
970 DepictFrameTree(root));
971 FrameTreeNode* grandchild = root->child_at(2)->child_at(0);
972 RenderFrameProxyHost* grandchild_rfph =
973 grandchild->render_manager()->GetRenderFrameProxyHost(b_site_instance);
974 EXPECT_FALSE(grandchild_rfph->is_render_frame_proxy_live());
976 // Navigate the second subframe to b.com to recreate process B.
977 TestNavigationObserver observer(shell()->web_contents());
978 GURL b_url = embedded_test_server()->GetURL("b.com", "/title1.html");
979 NavigateFrameToURL(root->child_at(1), b_url);
980 EXPECT_TRUE(observer.last_navigation_succeeded());
981 EXPECT_EQ(b_url, observer.last_navigation_url());
983 // Ensure that the grandchild RenderFrameProxy in B was created when process
984 // B was restored.
985 EXPECT_TRUE(grandchild_rfph->is_render_frame_proxy_live());
988 // In A-embed-B-embed-C scenario, verify that killing process B clears proxies
989 // of C from the tree.
991 // 1 A A
992 // / \ / \ / \ .
993 // 2 3 -> B A -> Kill B -> B* A
994 // / /
995 // 4 C
997 // node1 is the root.
998 // Initially, both node1.proxy_hosts_ and node3.proxy_hosts_ contain C.
999 // After we kill B, make sure proxies for C are cleared.
1000 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1001 KillingRendererClearsDescendantProxies) {
1002 GURL main_url(embedded_test_server()->GetURL(
1003 "a.com", "/frame_tree/page_with_two_frames_nested.html"));
1004 NavigateToURL(shell(), main_url);
1006 // It is safe to obtain the root frame tree node here, as it doesn't change.
1007 FrameTreeNode* root =
1008 static_cast<WebContentsImpl*>(shell()->web_contents())->
1009 GetFrameTree()->root();
1010 TestNavigationObserver observer(shell()->web_contents());
1012 ASSERT_EQ(2U, root->child_count());
1014 GURL site_b_url(
1015 embedded_test_server()->GetURL(
1016 "bar.com", "/frame_tree/page_with_one_frame.html"));
1017 // We can't use a TestNavigationObserver to verify the URL here,
1018 // since the frame has children that may have clobbered it in the observer.
1019 EXPECT_EQ(site_b_url, root->child_at(0)->current_url());
1021 // Ensure that a new process is created for node2.
1022 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1023 root->child_at(0)->current_frame_host()->GetSiteInstance());
1024 // Ensure that a new process is *not* created for node3.
1025 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
1026 root->child_at(1)->current_frame_host()->GetSiteInstance());
1028 ASSERT_EQ(1U, root->child_at(0)->child_count());
1030 // Make sure node4 points to the correct cross-site-page.
1031 FrameTreeNode* node4 = root->child_at(0)->child_at(0);
1032 GURL site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
1033 EXPECT_EQ(site_c_url, node4->current_url());
1035 // |site_instance_c|'s frames and proxies are expected to go away once we kill
1036 // |child_process_b| below.
1037 scoped_refptr<SiteInstanceImpl> site_instance_c =
1038 node4->current_frame_host()->GetSiteInstance();
1040 // Initially proxies for both B and C will be present in the root.
1041 EXPECT_EQ(
1042 " Site A ------------ proxies for B C\n"
1043 " |--Site B ------- proxies for A C\n"
1044 " | +--Site C -- proxies for A B\n"
1045 " +--Site A ------- proxies for B C\n"
1046 "Where A = http://a.com/\n"
1047 " B = http://bar.com/\n"
1048 " C = http://baz.com/",
1049 DepictFrameTree(root));
1051 EXPECT_GT(site_instance_c->active_frame_count(), 0U);
1053 // Kill process B.
1054 RenderProcessHost* child_process_b =
1055 root->child_at(0)->current_frame_host()->GetProcess();
1056 RenderProcessHostWatcher crash_observer(
1057 child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1058 child_process_b->Shutdown(0, false);
1059 crash_observer.Wait();
1061 // Make sure proxy C has gone from root.
1062 // Make sure proxy C has gone from node3 as well.
1063 // Make sure proxy B stays around in root and node3.
1064 EXPECT_EQ(
1065 " Site A ------------ proxies for B\n"
1066 " |--Site B ------- proxies for A\n"
1067 " +--Site A ------- proxies for B\n"
1068 "Where A = http://a.com/\n"
1069 " B = http://bar.com/ (no process)",
1070 DepictFrameTree(root));
1072 EXPECT_EQ(0U, site_instance_c->active_frame_count());
1075 // Crash a subframe and ensures its children are cleared from the FrameTree.
1076 // See http://crbug.com/338508.
1077 // TODO(creis): Disabled for flakiness; see http://crbug.com/405582.
1078 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DISABLED_CrashSubframe) {
1079 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1080 NavigateToURL(shell(), main_url);
1082 StartFrameAtDataURL();
1084 // These must stay in scope with replace_host.
1085 GURL::Replacements replace_host;
1086 std::string foo_com("foo.com");
1088 // Load cross-site page into iframe.
1089 EXPECT_TRUE(NavigateIframeToURL(
1090 shell()->web_contents(), "test",
1091 embedded_test_server()->GetURL("/cross-site/foo.com/title2.html")));
1093 // Check the subframe process.
1094 FrameTreeNode* root =
1095 static_cast<WebContentsImpl*>(shell()->web_contents())->
1096 GetFrameTree()->root();
1097 ASSERT_EQ(2U, root->child_count());
1098 FrameTreeNode* child = root->child_at(0);
1099 EXPECT_EQ(main_url, root->current_url());
1100 EXPECT_EQ("foo.com", child->current_url().host());
1101 EXPECT_EQ("/title2.html", child->current_url().path());
1103 EXPECT_TRUE(
1104 child->current_frame_host()->render_view_host()->IsRenderViewLive());
1105 EXPECT_TRUE(child->current_frame_host()->IsRenderFrameLive());
1107 // Crash the subframe process.
1108 RenderProcessHost* root_process = root->current_frame_host()->GetProcess();
1109 RenderProcessHost* child_process = child->current_frame_host()->GetProcess();
1111 RenderProcessHostWatcher crash_observer(
1112 child_process,
1113 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1114 child_process->Shutdown(0, false);
1115 crash_observer.Wait();
1118 // Ensure that the child frame still exists but has been cleared.
1119 EXPECT_EQ(2U, root->child_count());
1120 EXPECT_EQ(main_url, root->current_url());
1121 EXPECT_EQ(GURL(), child->current_url());
1123 EXPECT_FALSE(
1124 child->current_frame_host()->render_view_host()->IsRenderViewLive());
1125 EXPECT_FALSE(child->current_frame_host()->IsRenderFrameLive());
1126 EXPECT_FALSE(child->current_frame_host()->render_frame_created_);
1128 // Now crash the top-level page to clear the child frame.
1130 RenderProcessHostWatcher crash_observer(
1131 root_process,
1132 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1133 root_process->Shutdown(0, false);
1134 crash_observer.Wait();
1136 EXPECT_EQ(0U, root->child_count());
1137 EXPECT_EQ(GURL(), root->current_url());
1140 // When a new subframe is added, related SiteInstances that can reach the
1141 // subframe should create proxies for it (https://crbug.com/423587). This test
1142 // checks that if A embeds B and later adds a new subframe A2, A2 gets a proxy
1143 // in B's process.
1144 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CreateProxiesForNewFrames) {
1145 GURL main_url(embedded_test_server()->GetURL(
1146 "b.com", "/frame_tree/page_with_one_frame.html"));
1147 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1149 // It is safe to obtain the root frame tree node here, as it doesn't change.
1150 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1151 ->GetFrameTree()
1152 ->root();
1153 ASSERT_EQ(1U, root->child_count());
1155 // Make sure the frame starts out at the correct cross-site URL.
1156 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"),
1157 root->child_at(0)->current_url());
1159 EXPECT_EQ(
1160 " Site A ------------ proxies for B\n"
1161 " +--Site B ------- proxies for A\n"
1162 "Where A = http://b.com/\n"
1163 " B = http://baz.com/",
1164 DepictFrameTree(root));
1166 // Add a new child frame to the top-level frame.
1167 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 1);
1168 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1169 "window.domAutomationController.send("
1170 " addFrame('data:text/html,foo'));"));
1171 frame_observer.Wait();
1173 // The new frame should have a proxy in Site B, for use by the old frame.
1174 EXPECT_EQ(
1175 " Site A ------------ proxies for B\n"
1176 " |--Site B ------- proxies for A\n"
1177 " +--Site A ------- proxies for B\n"
1178 "Where A = http://b.com/\n"
1179 " B = http://baz.com/",
1180 DepictFrameTree(root));
1183 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
1184 // security checks are back in place.
1185 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
1186 // on Android (http://crbug.com/187570).
1187 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1188 DISABLED_CrossSiteIframeRedirectOnce) {
1189 ASSERT_TRUE(test_server()->Start());
1190 net::SpawnedTestServer https_server(
1191 net::SpawnedTestServer::TYPE_HTTPS,
1192 net::SpawnedTestServer::kLocalhost,
1193 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
1194 ASSERT_TRUE(https_server.Start());
1196 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
1197 GURL http_url(test_server()->GetURL("files/title1.html"));
1198 GURL https_url(https_server.GetURL("files/title1.html"));
1200 NavigateToURL(shell(), main_url);
1202 TestNavigationObserver observer(shell()->web_contents());
1204 // Load cross-site client-redirect page into Iframe.
1205 // Should be blocked.
1206 GURL client_redirect_https_url(https_server.GetURL(
1207 "client-redirect?files/title1.html"));
1208 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1209 client_redirect_https_url));
1210 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
1211 EXPECT_EQ(observer.last_navigation_url(), client_redirect_https_url);
1212 EXPECT_FALSE(observer.last_navigation_succeeded());
1216 // Load cross-site server-redirect page into Iframe,
1217 // which redirects to same-site page.
1218 GURL server_redirect_http_url(https_server.GetURL(
1219 "server-redirect?" + http_url.spec()));
1220 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1221 server_redirect_http_url));
1222 EXPECT_EQ(observer.last_navigation_url(), http_url);
1223 EXPECT_TRUE(observer.last_navigation_succeeded());
1227 // Load cross-site server-redirect page into Iframe,
1228 // which redirects to cross-site page.
1229 GURL server_redirect_http_url(https_server.GetURL(
1230 "server-redirect?files/title1.html"));
1231 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1232 server_redirect_http_url));
1233 // DidFailProvisionalLoad when navigating to https_url.
1234 EXPECT_EQ(observer.last_navigation_url(), https_url);
1235 EXPECT_FALSE(observer.last_navigation_succeeded());
1239 // Load same-site server-redirect page into Iframe,
1240 // which redirects to cross-site page.
1241 GURL server_redirect_http_url(test_server()->GetURL(
1242 "server-redirect?" + https_url.spec()));
1243 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1244 server_redirect_http_url));
1246 EXPECT_EQ(observer.last_navigation_url(), https_url);
1247 EXPECT_FALSE(observer.last_navigation_succeeded());
1251 // Load same-site client-redirect page into Iframe,
1252 // which redirects to cross-site page.
1253 GURL client_redirect_http_url(test_server()->GetURL(
1254 "client-redirect?" + https_url.spec()));
1256 RedirectNotificationObserver load_observer2(
1257 NOTIFICATION_LOAD_STOP,
1258 Source<NavigationController>(
1259 &shell()->web_contents()->GetController()));
1261 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1262 client_redirect_http_url));
1264 // Same-site Client-Redirect Page should be loaded successfully.
1265 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
1266 EXPECT_TRUE(observer.last_navigation_succeeded());
1268 // Redirecting to Cross-site Page should be blocked.
1269 load_observer2.Wait();
1270 EXPECT_EQ(observer.last_navigation_url(), https_url);
1271 EXPECT_FALSE(observer.last_navigation_succeeded());
1275 // Load same-site server-redirect page into Iframe,
1276 // which redirects to same-site page.
1277 GURL server_redirect_http_url(test_server()->GetURL(
1278 "server-redirect?files/title1.html"));
1279 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1280 server_redirect_http_url));
1281 EXPECT_EQ(observer.last_navigation_url(), http_url);
1282 EXPECT_TRUE(observer.last_navigation_succeeded());
1286 // Load same-site client-redirect page into Iframe,
1287 // which redirects to same-site page.
1288 GURL client_redirect_http_url(test_server()->GetURL(
1289 "client-redirect?" + http_url.spec()));
1290 RedirectNotificationObserver load_observer2(
1291 NOTIFICATION_LOAD_STOP,
1292 Source<NavigationController>(
1293 &shell()->web_contents()->GetController()));
1295 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1296 client_redirect_http_url));
1298 // Same-site Client-Redirect Page should be loaded successfully.
1299 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
1300 EXPECT_TRUE(observer.last_navigation_succeeded());
1302 // Redirecting to Same-site Page should be loaded successfully.
1303 load_observer2.Wait();
1304 EXPECT_EQ(observer.last_navigation_url(), http_url);
1305 EXPECT_TRUE(observer.last_navigation_succeeded());
1309 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
1310 // security checks are back in place.
1311 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
1312 // on Android (http://crbug.com/187570).
1313 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1314 DISABLED_CrossSiteIframeRedirectTwice) {
1315 ASSERT_TRUE(test_server()->Start());
1316 net::SpawnedTestServer https_server(
1317 net::SpawnedTestServer::TYPE_HTTPS,
1318 net::SpawnedTestServer::kLocalhost,
1319 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
1320 ASSERT_TRUE(https_server.Start());
1322 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
1323 GURL http_url(test_server()->GetURL("files/title1.html"));
1324 GURL https_url(https_server.GetURL("files/title1.html"));
1326 NavigateToURL(shell(), main_url);
1328 TestNavigationObserver observer(shell()->web_contents());
1330 // Load client-redirect page pointing to a cross-site client-redirect page,
1331 // which eventually redirects back to same-site page.
1332 GURL client_redirect_https_url(https_server.GetURL(
1333 "client-redirect?" + http_url.spec()));
1334 GURL client_redirect_http_url(test_server()->GetURL(
1335 "client-redirect?" + client_redirect_https_url.spec()));
1337 // We should wait until second client redirect get cancelled.
1338 RedirectNotificationObserver load_observer2(
1339 NOTIFICATION_LOAD_STOP,
1340 Source<NavigationController>(
1341 &shell()->web_contents()->GetController()));
1343 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1344 client_redirect_http_url));
1346 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
1347 load_observer2.Wait();
1348 EXPECT_EQ(observer.last_navigation_url(), client_redirect_https_url);
1349 EXPECT_FALSE(observer.last_navigation_succeeded());
1353 // Load server-redirect page pointing to a cross-site server-redirect page,
1354 // which eventually redirect back to same-site page.
1355 GURL server_redirect_https_url(https_server.GetURL(
1356 "server-redirect?" + http_url.spec()));
1357 GURL server_redirect_http_url(test_server()->GetURL(
1358 "server-redirect?" + server_redirect_https_url.spec()));
1359 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1360 server_redirect_http_url));
1361 EXPECT_EQ(observer.last_navigation_url(), http_url);
1362 EXPECT_TRUE(observer.last_navigation_succeeded());
1366 // Load server-redirect page pointing to a cross-site server-redirect page,
1367 // which eventually redirects back to cross-site page.
1368 GURL server_redirect_https_url(https_server.GetURL(
1369 "server-redirect?" + https_url.spec()));
1370 GURL server_redirect_http_url(test_server()->GetURL(
1371 "server-redirect?" + server_redirect_https_url.spec()));
1372 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1373 server_redirect_http_url));
1375 // DidFailProvisionalLoad when navigating to https_url.
1376 EXPECT_EQ(observer.last_navigation_url(), https_url);
1377 EXPECT_FALSE(observer.last_navigation_succeeded());
1381 // Load server-redirect page pointing to a cross-site client-redirect page,
1382 // which eventually redirects back to same-site page.
1383 GURL client_redirect_http_url(https_server.GetURL(
1384 "client-redirect?" + http_url.spec()));
1385 GURL server_redirect_http_url(test_server()->GetURL(
1386 "server-redirect?" + client_redirect_http_url.spec()));
1387 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1388 server_redirect_http_url));
1390 // DidFailProvisionalLoad when navigating to client_redirect_http_url.
1391 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
1392 EXPECT_FALSE(observer.last_navigation_succeeded());
1396 // Ensure that when navigating a frame cross-process RenderFrameProxyHosts are
1397 // created in the FrameTree skipping the subtree of the navigating frame.
1398 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1399 ProxyCreationSkipsSubtree) {
1400 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1401 NavigateToURL(shell(), main_url);
1403 // It is safe to obtain the root frame tree node here, as it doesn't change.
1404 FrameTreeNode* root =
1405 static_cast<WebContentsImpl*>(shell()->web_contents())->
1406 GetFrameTree()->root();
1408 EXPECT_TRUE(root->child_at(1) != NULL);
1409 EXPECT_EQ(2U, root->child_at(1)->child_count());
1412 // Load same-site page into iframe.
1413 TestNavigationObserver observer(shell()->web_contents());
1414 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
1415 NavigateFrameToURL(root->child_at(0), http_url);
1416 EXPECT_EQ(http_url, observer.last_navigation_url());
1417 EXPECT_TRUE(observer.last_navigation_succeeded());
1418 EXPECT_EQ(
1419 " Site A\n"
1420 " |--Site A\n"
1421 " +--Site A\n"
1422 " |--Site A\n"
1423 " +--Site A\n"
1424 " +--Site A\n"
1425 "Where A = http://127.0.0.1/",
1426 DepictFrameTree(root));
1429 // Create the cross-site URL to navigate to.
1430 GURL cross_site_url =
1431 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html");
1433 // Load cross-site page into the second iframe without waiting for the
1434 // navigation to complete. Once LoadURLWithParams returns, we would expect
1435 // proxies to have been created in the frame tree, but children of the
1436 // navigating frame to still be present. The reason is that we don't run the
1437 // message loop, so no IPCs that alter the frame tree can be processed.
1438 FrameTreeNode* child = root->child_at(1);
1439 SiteInstance* site = NULL;
1441 TestNavigationObserver observer(shell()->web_contents());
1442 TestFrameNavigationObserver navigation_observer(child);
1443 NavigationController::LoadURLParams params(cross_site_url);
1444 params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
1445 params.frame_tree_node_id = child->frame_tree_node_id();
1446 child->navigator()->GetController()->LoadURLWithParams(params);
1448 site = child->render_manager()->pending_frame_host()->GetSiteInstance();
1449 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site);
1451 EXPECT_EQ(
1452 " Site A ------------ proxies for B\n"
1453 " |--Site A ------- proxies for B\n"
1454 " +--Site A (B pending)\n"
1455 " |--Site A\n"
1456 " +--Site A\n"
1457 " +--Site A\n"
1458 "Where A = http://127.0.0.1/\n"
1459 " B = http://foo.com/",
1460 DepictFrameTree(root));
1462 // Now that the verification is done, run the message loop and wait for the
1463 // navigation to complete.
1464 navigation_observer.Wait();
1465 EXPECT_FALSE(child->render_manager()->pending_frame_host());
1466 EXPECT_TRUE(observer.last_navigation_succeeded());
1467 EXPECT_EQ(cross_site_url, observer.last_navigation_url());
1469 EXPECT_EQ(
1470 " Site A ------------ proxies for B\n"
1471 " |--Site A ------- proxies for B\n"
1472 " +--Site B ------- proxies for A\n"
1473 "Where A = http://127.0.0.1/\n"
1474 " B = http://foo.com/",
1475 DepictFrameTree(root));
1478 // Load another cross-site page into the same iframe.
1479 cross_site_url = embedded_test_server()->GetURL("bar.com", "/title2.html");
1481 // Perform the same checks as the first cross-site navigation, since
1482 // there have been issues in subsequent cross-site navigations. Also ensure
1483 // that the SiteInstance has properly changed.
1484 // TODO(nasko): Once we have proper cleanup of resources, add code to
1485 // verify that the intermediate SiteInstance/RenderFrameHost have been
1486 // properly cleaned up.
1487 TestNavigationObserver observer(shell()->web_contents());
1488 TestFrameNavigationObserver navigation_observer(child);
1489 NavigationController::LoadURLParams params(cross_site_url);
1490 params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
1491 params.frame_tree_node_id = child->frame_tree_node_id();
1492 child->navigator()->GetController()->LoadURLWithParams(params);
1494 SiteInstance* site2 =
1495 child->render_manager()->pending_frame_host()->GetSiteInstance();
1496 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site2);
1497 EXPECT_NE(site, site2);
1499 EXPECT_EQ(
1500 " Site A ------------ proxies for B C\n"
1501 " |--Site A ------- proxies for B C\n"
1502 " +--Site B (C pending) -- proxies for A\n"
1503 "Where A = http://127.0.0.1/\n"
1504 " B = http://foo.com/\n"
1505 " C = http://bar.com/",
1506 DepictFrameTree(root));
1508 navigation_observer.Wait();
1509 EXPECT_TRUE(observer.last_navigation_succeeded());
1510 EXPECT_EQ(cross_site_url, observer.last_navigation_url());
1511 EXPECT_EQ(0U, child->child_count());
1515 // Verify that origin replication works for an A-embed-B-embed-C hierarchy.
1516 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OriginReplication) {
1517 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1518 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1520 // It is safe to obtain the root frame tree node here, as it doesn't change.
1521 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1522 ->GetFrameTree()
1523 ->root();
1525 TestNavigationObserver observer(shell()->web_contents());
1527 // Navigate the first subframe to a cross-site page with two subframes.
1528 GURL foo_url(
1529 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
1530 NavigateFrameToURL(root->child_at(0), foo_url);
1531 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1533 // We can't use a TestNavigationObserver to verify the URL here,
1534 // since the frame has children that may have clobbered it in the observer.
1535 EXPECT_EQ(foo_url, root->child_at(0)->current_url());
1537 // Ensure that a new process is created for the subframe.
1538 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1539 root->child_at(0)->current_frame_host()->GetSiteInstance());
1541 // Load cross-site page into subframe's subframe.
1542 ASSERT_EQ(2U, root->child_at(0)->child_count());
1543 GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
1544 NavigateFrameToURL(root->child_at(0)->child_at(0), bar_url);
1545 EXPECT_TRUE(observer.last_navigation_succeeded());
1546 EXPECT_EQ(bar_url, observer.last_navigation_url());
1548 // Check that a new process is created and is different from the top one and
1549 // the middle one.
1550 FrameTreeNode* bottom_child = root->child_at(0)->child_at(0);
1551 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1552 bottom_child->current_frame_host()->GetSiteInstance());
1553 EXPECT_NE(root->child_at(0)->current_frame_host()->GetSiteInstance(),
1554 bottom_child->current_frame_host()->GetSiteInstance());
1556 // Check that foo.com frame's location.ancestorOrigins contains the correct
1557 // origin for the parent. The origin should have been replicated as part of
1558 // the ViewMsg_New message that created the parent's RenderFrameProxy in
1559 // foo.com's process.
1560 int ancestor_origins_length = 0;
1561 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1562 root->child_at(0)->current_frame_host(),
1563 "window.domAutomationController.send(location.ancestorOrigins.length);",
1564 &ancestor_origins_length));
1565 EXPECT_EQ(1, ancestor_origins_length);
1566 std::string result;
1567 EXPECT_TRUE(ExecuteScriptAndExtractString(
1568 root->child_at(0)->current_frame_host(),
1569 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1570 &result));
1571 EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
1573 // Check that bar.com frame's location.ancestorOrigins contains the correct
1574 // origin for its two ancestors. The topmost parent origin should be
1575 // replicated as part of ViewMsg_New, and the middle frame (foo.com's) origin
1576 // should be replicated as part of FrameMsg_NewFrameProxy sent for foo.com's
1577 // frame in bar.com's process.
1578 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1579 bottom_child->current_frame_host(),
1580 "window.domAutomationController.send(location.ancestorOrigins.length);",
1581 &ancestor_origins_length));
1582 EXPECT_EQ(2, ancestor_origins_length);
1583 EXPECT_TRUE(ExecuteScriptAndExtractString(
1584 bottom_child->current_frame_host(),
1585 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1586 &result));
1587 EXPECT_EQ(result + "/", foo_url.GetOrigin().spec());
1588 EXPECT_TRUE(ExecuteScriptAndExtractString(
1589 bottom_child->current_frame_host(),
1590 "window.domAutomationController.send(location.ancestorOrigins[1]);",
1591 &result));
1592 EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
1595 // Check that iframe sandbox flags are replicated correctly.
1596 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SandboxFlagsReplication) {
1597 GURL main_url(embedded_test_server()->GetURL("/sandboxed_frames.html"));
1598 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1600 // It is safe to obtain the root frame tree node here, as it doesn't change.
1601 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1602 ->GetFrameTree()
1603 ->root();
1605 TestNavigationObserver observer(shell()->web_contents());
1607 // Navigate the second (sandboxed) subframe to a cross-site page with a
1608 // subframe.
1609 GURL foo_url(
1610 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
1611 NavigateFrameToURL(root->child_at(1), foo_url);
1612 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1614 // We can't use a TestNavigationObserver to verify the URL here,
1615 // since the frame has children that may have clobbered it in the observer.
1616 EXPECT_EQ(foo_url, root->child_at(1)->current_url());
1618 // Load cross-site page into subframe's subframe.
1619 ASSERT_EQ(2U, root->child_at(1)->child_count());
1620 GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
1621 NavigateFrameToURL(root->child_at(1)->child_at(0), bar_url);
1622 EXPECT_TRUE(observer.last_navigation_succeeded());
1623 EXPECT_EQ(bar_url, observer.last_navigation_url());
1625 // Opening a popup in the sandboxed foo.com iframe should fail.
1626 bool success = false;
1627 EXPECT_TRUE(
1628 ExecuteScriptAndExtractBool(root->child_at(1)->current_frame_host(),
1629 "window.domAutomationController.send("
1630 "!window.open('data:text/html,dataurl'));",
1631 &success));
1632 EXPECT_TRUE(success);
1633 EXPECT_EQ(1u, Shell::windows().size());
1635 // Opening a popup in a frame whose parent is sandboxed should also fail.
1636 // Here, bar.com frame's sandboxed parent frame is a remote frame in
1637 // bar.com's process.
1638 success = false;
1639 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1640 root->child_at(1)->child_at(0)->current_frame_host(),
1641 "window.domAutomationController.send("
1642 "!window.open('data:text/html,dataurl'));",
1643 &success));
1644 EXPECT_TRUE(success);
1645 EXPECT_EQ(1u, Shell::windows().size());
1647 // Same, but now try the case where bar.com frame's sandboxed parent is a
1648 // local frame in bar.com's process.
1649 success = false;
1650 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1651 root->child_at(2)->child_at(0)->current_frame_host(),
1652 "window.domAutomationController.send("
1653 "!window.open('data:text/html,dataurl'));",
1654 &success));
1655 EXPECT_TRUE(success);
1656 EXPECT_EQ(1u, Shell::windows().size());
1658 // Check that foo.com frame's location.ancestorOrigins contains the correct
1659 // origin for the parent, which should be unaffected by sandboxing.
1660 int ancestor_origins_length = 0;
1661 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1662 root->child_at(1)->current_frame_host(),
1663 "window.domAutomationController.send(location.ancestorOrigins.length);",
1664 &ancestor_origins_length));
1665 EXPECT_EQ(1, ancestor_origins_length);
1666 std::string result;
1667 EXPECT_TRUE(ExecuteScriptAndExtractString(
1668 root->child_at(1)->current_frame_host(),
1669 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1670 &result));
1671 EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
1673 // Now check location.ancestorOrigins for the bar.com frame. The middle frame
1674 // (foo.com's) origin should be unique, since that frame is sandboxed, and
1675 // the top frame should match |main_url|.
1676 FrameTreeNode* bottom_child = root->child_at(1)->child_at(0);
1677 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1678 bottom_child->current_frame_host(),
1679 "window.domAutomationController.send(location.ancestorOrigins.length);",
1680 &ancestor_origins_length));
1681 EXPECT_EQ(2, ancestor_origins_length);
1682 EXPECT_TRUE(ExecuteScriptAndExtractString(
1683 bottom_child->current_frame_host(),
1684 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1685 &result));
1686 EXPECT_EQ("null", result);
1687 EXPECT_TRUE(ExecuteScriptAndExtractString(
1688 bottom_child->current_frame_host(),
1689 "window.domAutomationController.send(location.ancestorOrigins[1]);",
1690 &result));
1691 EXPECT_EQ(main_url.GetOrigin().spec(), result + "/");
1694 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
1695 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicSandboxFlags) {
1696 GURL main_url(
1697 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
1698 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1700 // It is safe to obtain the root frame tree node here, as it doesn't change.
1701 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1702 ->GetFrameTree()
1703 ->root();
1705 TestNavigationObserver observer(shell()->web_contents());
1706 ASSERT_EQ(2U, root->child_count());
1708 // Make sure first frame starts out at the correct cross-site page.
1709 EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"),
1710 root->child_at(0)->current_url());
1712 // Navigate second frame to another cross-site page.
1713 GURL baz_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
1714 NavigateFrameToURL(root->child_at(1), baz_url);
1715 EXPECT_TRUE(observer.last_navigation_succeeded());
1716 EXPECT_EQ(baz_url, observer.last_navigation_url());
1718 // Both frames should not be sandboxed to start with.
1719 EXPECT_EQ(blink::WebSandboxFlags::None,
1720 root->child_at(0)->current_replication_state().sandbox_flags);
1721 EXPECT_EQ(blink::WebSandboxFlags::None,
1722 root->child_at(0)->effective_sandbox_flags());
1723 EXPECT_EQ(blink::WebSandboxFlags::None,
1724 root->child_at(1)->current_replication_state().sandbox_flags);
1725 EXPECT_EQ(blink::WebSandboxFlags::None,
1726 root->child_at(1)->effective_sandbox_flags());
1728 // Dynamically update sandbox flags for the first frame.
1729 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1730 "window.domAutomationController.send("
1731 "document.querySelector('iframe').sandbox="
1732 "'allow-scripts');"));
1734 // Check that updated sandbox flags are propagated to browser process.
1735 // The new flags should be set in current_replication_state(), while
1736 // effective_sandbox_flags() should still reflect the old flags, because
1737 // sandbox flag updates take place only after navigations. "allow-scripts"
1738 // resets both SandboxFlags::Scripts and SandboxFlags::AutomaticFeatures bits
1739 // per blink::parseSandboxPolicy().
1740 blink::WebSandboxFlags expected_flags =
1741 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
1742 ~blink::WebSandboxFlags::AutomaticFeatures;
1743 EXPECT_EQ(expected_flags,
1744 root->child_at(0)->current_replication_state().sandbox_flags);
1745 EXPECT_EQ(blink::WebSandboxFlags::None,
1746 root->child_at(0)->effective_sandbox_flags());
1748 // Navigate the first frame to a page on the same site. The new sandbox
1749 // flags should take effect.
1750 GURL bar_url(
1751 embedded_test_server()->GetURL("bar.com", "/frame_tree/2-4.html"));
1752 NavigateFrameToURL(root->child_at(0), bar_url);
1753 // (The new page has a subframe; wait for it to load as well.)
1754 ASSERT_TRUE(WaitForLoadStop(shell()->web_contents()));
1755 EXPECT_EQ(bar_url, root->child_at(0)->current_url());
1756 ASSERT_EQ(1U, root->child_at(0)->child_count());
1758 EXPECT_EQ(
1759 " Site A ------------ proxies for B C\n"
1760 " |--Site B ------- proxies for A C\n"
1761 " | +--Site B -- proxies for A C\n"
1762 " +--Site C ------- proxies for A B\n"
1763 "Where A = http://127.0.0.1/\n"
1764 " B = http://bar.com/\n"
1765 " C = http://baz.com/",
1766 DepictFrameTree(root));
1768 // Confirm that the browser process has updated the frame's current sandbox
1769 // flags.
1770 EXPECT_EQ(expected_flags,
1771 root->child_at(0)->current_replication_state().sandbox_flags);
1772 EXPECT_EQ(expected_flags, root->child_at(0)->effective_sandbox_flags());
1774 // Opening a popup in the now-sandboxed frame should fail.
1775 bool success = false;
1776 EXPECT_TRUE(
1777 ExecuteScriptAndExtractBool(root->child_at(0)->current_frame_host(),
1778 "window.domAutomationController.send("
1779 "!window.open('data:text/html,dataurl'));",
1780 &success));
1781 EXPECT_TRUE(success);
1782 EXPECT_EQ(1u, Shell::windows().size());
1784 // Navigate the child of the now-sandboxed frame to a page on baz.com. The
1785 // child should inherit the latest sandbox flags from its parent frame, which
1786 // is currently a proxy in baz.com's renderer process. This checks that the
1787 // proxies of |root->child_at(0)| were also updated with the latest sandbox
1788 // flags.
1789 GURL baz_child_url(embedded_test_server()->GetURL("baz.com", "/title2.html"));
1790 NavigateFrameToURL(root->child_at(0)->child_at(0), baz_child_url);
1791 EXPECT_TRUE(observer.last_navigation_succeeded());
1792 EXPECT_EQ(baz_child_url, observer.last_navigation_url());
1794 EXPECT_EQ(
1795 " Site A ------------ proxies for B C\n"
1796 " |--Site B ------- proxies for A C\n"
1797 " | +--Site C -- proxies for A B\n"
1798 " +--Site C ------- proxies for A B\n"
1799 "Where A = http://127.0.0.1/\n"
1800 " B = http://bar.com/\n"
1801 " C = http://baz.com/",
1802 DepictFrameTree(root));
1804 // Opening a popup in the child of a sandboxed frame should fail.
1805 success = false;
1806 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1807 root->child_at(0)->child_at(0)->current_frame_host(),
1808 "window.domAutomationController.send("
1809 "!window.open('data:text/html,dataurl'));",
1810 &success));
1811 EXPECT_TRUE(success);
1812 EXPECT_EQ(1u, Shell::windows().size());
1815 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
1816 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1817 DynamicSandboxFlagsRemoteToLocal) {
1818 GURL main_url(
1819 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
1820 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1822 // It is safe to obtain the root frame tree node here, as it doesn't change.
1823 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1824 ->GetFrameTree()
1825 ->root();
1827 TestNavigationObserver observer(shell()->web_contents());
1828 ASSERT_EQ(2U, root->child_count());
1830 // Make sure the two frames starts out at correct URLs.
1831 EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"),
1832 root->child_at(0)->current_url());
1833 EXPECT_EQ(embedded_test_server()->GetURL("/title1.html"),
1834 root->child_at(1)->current_url());
1836 // Update the second frame's sandbox flags.
1837 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1838 "window.domAutomationController.send("
1839 "document.querySelectorAll('iframe')[1].sandbox="
1840 "'allow-scripts');"));
1842 // Check that the current sandbox flags are updated but the effective
1843 // sandbox flags are not.
1844 blink::WebSandboxFlags expected_flags =
1845 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
1846 ~blink::WebSandboxFlags::AutomaticFeatures;
1847 EXPECT_EQ(expected_flags,
1848 root->child_at(1)->current_replication_state().sandbox_flags);
1849 EXPECT_EQ(blink::WebSandboxFlags::None,
1850 root->child_at(1)->effective_sandbox_flags());
1852 // Navigate the second subframe to a page on bar.com. This will trigger a
1853 // remote-to-local frame swap in bar.com's process. The target page has
1854 // another frame, so use TestFrameNavigationObserver to wait for all frames
1855 // to be loaded.
1856 TestFrameNavigationObserver frame_observer(root->child_at(1), 2);
1857 GURL bar_url(embedded_test_server()->GetURL(
1858 "bar.com", "/frame_tree/page_with_one_frame.html"));
1859 NavigateFrameToURL(root->child_at(1), bar_url);
1860 frame_observer.Wait();
1861 EXPECT_EQ(bar_url, root->child_at(1)->current_url());
1862 ASSERT_EQ(1U, root->child_at(1)->child_count());
1864 // Confirm that the browser process has updated the current sandbox flags.
1865 EXPECT_EQ(expected_flags,
1866 root->child_at(1)->current_replication_state().sandbox_flags);
1867 EXPECT_EQ(expected_flags, root->child_at(1)->effective_sandbox_flags());
1869 // Opening a popup in the sandboxed second frame should fail.
1870 bool success = false;
1871 EXPECT_TRUE(
1872 ExecuteScriptAndExtractBool(root->child_at(1)->current_frame_host(),
1873 "window.domAutomationController.send("
1874 "!window.open('data:text/html,dataurl'));",
1875 &success));
1876 EXPECT_TRUE(success);
1877 EXPECT_EQ(1u, Shell::windows().size());
1879 // Make sure that the child frame inherits the sandbox flags of its
1880 // now-sandboxed parent frame.
1881 success = false;
1882 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1883 root->child_at(1)->child_at(0)->current_frame_host(),
1884 "window.domAutomationController.send("
1885 "!window.open('data:text/html,dataurl'));",
1886 &success));
1887 EXPECT_TRUE(success);
1888 EXPECT_EQ(1u, Shell::windows().size());
1891 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
1892 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1893 DynamicSandboxFlagsRendererInitiatedNavigation) {
1894 GURL main_url(
1895 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
1896 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1898 // It is safe to obtain the root frame tree node here, as it doesn't change.
1899 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1900 ->GetFrameTree()
1901 ->root();
1903 TestNavigationObserver observer(shell()->web_contents());
1904 ASSERT_EQ(1U, root->child_count());
1906 // Make sure the frame starts out at the correct cross-site page.
1907 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"),
1908 root->child_at(0)->current_url());
1910 // The frame should not be sandboxed to start with.
1911 EXPECT_EQ(blink::WebSandboxFlags::None,
1912 root->child_at(0)->current_replication_state().sandbox_flags);
1913 EXPECT_EQ(blink::WebSandboxFlags::None,
1914 root->child_at(0)->effective_sandbox_flags());
1916 // Dynamically update the frame's sandbox flags.
1917 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1918 "window.domAutomationController.send("
1919 "document.querySelector('iframe').sandbox="
1920 "'allow-scripts');"));
1922 // Check that updated sandbox flags are propagated to browser process.
1923 // The new flags should be set in current_replication_state(), while
1924 // effective_sandbox_flags() should still reflect the old flags, because
1925 // sandbox flag updates take place only after navigations. "allow-scripts"
1926 // resets both SandboxFlags::Scripts and SandboxFlags::AutomaticFeatures bits
1927 // per blink::parseSandboxPolicy().
1928 blink::WebSandboxFlags expected_flags =
1929 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
1930 ~blink::WebSandboxFlags::AutomaticFeatures;
1931 EXPECT_EQ(expected_flags,
1932 root->child_at(0)->current_replication_state().sandbox_flags);
1933 EXPECT_EQ(blink::WebSandboxFlags::None,
1934 root->child_at(0)->effective_sandbox_flags());
1936 // Perform a renderer-initiated same-site navigation in the first frame. The
1937 // new sandbox flags should take effect.
1938 TestFrameNavigationObserver frame_observer(root->child_at(0));
1939 ASSERT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
1940 "window.location.href='/title2.html'"));
1941 frame_observer.Wait();
1942 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title2.html"),
1943 root->child_at(0)->current_url());
1945 // Confirm that the browser process has updated the frame's current sandbox
1946 // flags.
1947 EXPECT_EQ(expected_flags,
1948 root->child_at(0)->current_replication_state().sandbox_flags);
1949 EXPECT_EQ(expected_flags, root->child_at(0)->effective_sandbox_flags());
1951 // Opening a popup in the now-sandboxed frame should fail.
1952 bool success = false;
1953 EXPECT_TRUE(
1954 ExecuteScriptAndExtractBool(root->child_at(0)->current_frame_host(),
1955 "window.domAutomationController.send("
1956 "!window.open('data:text/html,dataurl'));",
1957 &success));
1958 EXPECT_TRUE(success);
1959 EXPECT_EQ(1u, Shell::windows().size());
1962 // Verify that when a new child frame is added, the proxies created for it in
1963 // other SiteInstances have correct sandbox flags and origin.
1965 // A A A
1966 // / / \ / \ .
1967 // B -> B A -> B A
1968 // \ .
1969 // B
1971 // The test checks sandbox flags and origin for the proxy added in step 2, by
1972 // checking whether the grandchild frame added in step 3 sees proper sandbox
1973 // flags and origin for its (remote) parent. This wasn't addressed when
1974 // https://crbug.com/423587 was fixed.
1975 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1976 ProxiesForNewChildFramesHaveCorrectReplicationState) {
1977 GURL main_url(
1978 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
1979 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1981 // It is safe to obtain the root frame tree node here, as it doesn't change.
1982 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1983 ->GetFrameTree()
1984 ->root();
1985 TestNavigationObserver observer(shell()->web_contents());
1987 EXPECT_EQ(
1988 " Site A ------------ proxies for B\n"
1989 " +--Site B ------- proxies for A\n"
1990 "Where A = http://127.0.0.1/\n"
1991 " B = http://baz.com/",
1992 DepictFrameTree(root));
1994 // In the root frame, add a new sandboxed local frame, which itself has a
1995 // child frame on baz.com. Wait for three RenderFrameHosts to be created:
1996 // the new sandboxed local frame, its child (while it's still local), and a
1997 // pending RFH when starting the cross-site navigation to baz.com.
1998 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 3);
1999 EXPECT_TRUE(
2000 ExecuteScript(root->current_frame_host(),
2001 "window.domAutomationController.send("
2002 " addFrame('/frame_tree/page_with_one_frame.html',"
2003 " 'allow-scripts allow-same-origin'))"));
2004 frame_observer.Wait();
2006 // Wait for the cross-site navigation to baz.com in the grandchild to finish.
2007 FrameTreeNode* bottom_child = root->child_at(1)->child_at(0);
2008 TestFrameNavigationObserver navigation_observer(bottom_child);
2009 navigation_observer.Wait();
2011 EXPECT_EQ(
2012 " Site A ------------ proxies for B\n"
2013 " |--Site B ------- proxies for A\n"
2014 " +--Site A ------- proxies for B\n"
2015 " +--Site B -- proxies for A\n"
2016 "Where A = http://127.0.0.1/\n"
2017 " B = http://baz.com/",
2018 DepictFrameTree(root));
2020 // Use location.ancestorOrigins to check that the grandchild on baz.com sees
2021 // correct origin for its parent.
2022 int ancestor_origins_length = 0;
2023 EXPECT_TRUE(ExecuteScriptAndExtractInt(
2024 bottom_child->current_frame_host(),
2025 "window.domAutomationController.send(location.ancestorOrigins.length);",
2026 &ancestor_origins_length));
2027 EXPECT_EQ(2, ancestor_origins_length);
2028 std::string parent_origin;
2029 EXPECT_TRUE(ExecuteScriptAndExtractString(
2030 bottom_child->current_frame_host(),
2031 "window.domAutomationController.send(location.ancestorOrigins[0]);",
2032 &parent_origin));
2033 EXPECT_EQ(main_url.GetOrigin().spec(), parent_origin + "/");
2035 // Check that the sandbox flags in the browser process are correct.
2036 // "allow-scripts" resets both WebSandboxFlags::Scripts and
2037 // WebSandboxFlags::AutomaticFeatures bits per blink::parseSandboxPolicy().
2038 blink::WebSandboxFlags expected_flags =
2039 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
2040 ~blink::WebSandboxFlags::AutomaticFeatures &
2041 ~blink::WebSandboxFlags::Origin;
2042 EXPECT_EQ(expected_flags,
2043 root->child_at(1)->current_replication_state().sandbox_flags);
2045 // The child of the sandboxed frame should've inherited sandbox flags, so it
2046 // should not be able to create popups.
2047 bool success = false;
2048 EXPECT_TRUE(
2049 ExecuteScriptAndExtractBool(bottom_child->current_frame_host(),
2050 "window.domAutomationController.send("
2051 "!window.open('data:text/html,dataurl'));",
2052 &success));
2053 EXPECT_TRUE(success);
2054 EXPECT_EQ(1u, Shell::windows().size());
2057 // Verify that a child frame can retrieve the name property set by its parent.
2058 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, WindowNameReplication) {
2059 GURL main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html"));
2060 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2062 // It is safe to obtain the root frame tree node here, as it doesn't change.
2063 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2064 ->GetFrameTree()
2065 ->root();
2067 TestNavigationObserver observer(shell()->web_contents());
2069 // Load cross-site page into iframe.
2070 GURL frame_url =
2071 embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html");
2072 NavigateFrameToURL(root->child_at(0), frame_url);
2073 EXPECT_TRUE(observer.last_navigation_succeeded());
2074 EXPECT_EQ(frame_url, observer.last_navigation_url());
2076 // Ensure that a new process is created for the subframe.
2077 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
2078 root->child_at(0)->current_frame_host()->GetSiteInstance());
2080 // Check that the window.name seen by the frame matches the name attribute
2081 // specified by its parent in the iframe tag.
2082 std::string result;
2083 EXPECT_TRUE(ExecuteScriptAndExtractString(
2084 root->child_at(0)->current_frame_host(),
2085 "window.domAutomationController.send(window.name);", &result));
2086 EXPECT_EQ("3-1-name", result);
2089 // Verify that dynamic updates to a frame's window.name propagate to the
2090 // frame's proxies, so that the latest frame names can be used in navigations.
2091 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicWindowName) {
2092 GURL main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html"));
2093 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2095 // It is safe to obtain the root frame tree node here, as it doesn't change.
2096 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2097 ->GetFrameTree()
2098 ->root();
2099 TestNavigationObserver observer(shell()->web_contents());
2101 // Load cross-site page into iframe.
2102 GURL frame_url =
2103 embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html");
2104 NavigateFrameToURL(root->child_at(0), frame_url);
2105 EXPECT_TRUE(observer.last_navigation_succeeded());
2106 EXPECT_EQ(frame_url, observer.last_navigation_url());
2108 // Browser process should know the child frame's original window.name
2109 // specified in the iframe element.
2110 EXPECT_EQ(root->child_at(0)->frame_name(), "3-1-name");
2112 // Update the child frame's window.name.
2113 EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
2114 "window.domAutomationController.send("
2115 "window.name = 'updated-name');"));
2117 // The change should propagate to the browser process.
2118 EXPECT_EQ(root->child_at(0)->frame_name(), "updated-name");
2120 // The proxy in the parent process should also receive the updated name.
2121 // Check that it can reference the child frame by its new name.
2122 bool success = false;
2123 EXPECT_TRUE(
2124 ExecuteScriptAndExtractBool(shell()->web_contents(),
2125 "window.domAutomationController.send("
2126 "frames['updated-name'] == frames[0]);",
2127 &success));
2128 EXPECT_TRUE(success);
2130 // Issue a renderer-initiated navigation from the root frame to the child
2131 // frame using the frame's name. Make sure correct frame is navigated.
2133 // TODO(alexmos): When blink::createWindow is refactored to handle
2134 // RemoteFrames, this should also be tested via window.open(url, frame_name)
2135 // and a more complicated frame hierarchy (https://crbug.com/463742)
2136 TestFrameNavigationObserver frame_observer(root->child_at(0));
2137 GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
2138 std::string script = base::StringPrintf(
2139 "window.domAutomationController.send("
2140 "frames['updated-name'].location.href = '%s');",
2141 foo_url.spec().c_str());
2142 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), script));
2143 frame_observer.Wait();
2144 EXPECT_EQ(foo_url, root->child_at(0)->current_url());
2147 // Verify that when a frame is navigated to a new origin, the origin update
2148 // propagates to the frame's proxies.
2149 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OriginUpdatesReachProxies) {
2150 GURL main_url(
2151 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
2152 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2154 // It is safe to obtain the root frame tree node here, as it doesn't change.
2155 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2156 ->GetFrameTree()
2157 ->root();
2158 TestNavigationObserver observer(shell()->web_contents());
2160 EXPECT_EQ(
2161 " Site A ------------ proxies for B\n"
2162 " |--Site B ------- proxies for A\n"
2163 " +--Site A ------- proxies for B\n"
2164 "Where A = http://127.0.0.1/\n"
2165 " B = http://bar.com/",
2166 DepictFrameTree(root));
2168 // Navigate second subframe to a baz.com. This should send an origin update
2169 // to the frame's proxy in the bar.com (first frame's) process.
2170 GURL frame_url = embedded_test_server()->GetURL("baz.com", "/title2.html");
2171 NavigateFrameToURL(root->child_at(1), frame_url);
2172 EXPECT_TRUE(observer.last_navigation_succeeded());
2173 EXPECT_EQ(frame_url, observer.last_navigation_url());
2175 // The first frame can't directly observe the second frame's origin with
2176 // JavaScript. Instead, try to navigate the second frame from the first
2177 // frame. This should fail with a console error message, which should
2178 // contain the second frame's updated origin (see blink::Frame::canNavigate).
2179 scoped_ptr<ConsoleObserverDelegate> console_delegate(
2180 new ConsoleObserverDelegate(
2181 shell()->web_contents(),
2182 "Unsafe JavaScript attempt to initiate navigation*"));
2183 shell()->web_contents()->SetDelegate(console_delegate.get());
2185 // frames[1] can't be used due to a bug where RemoteFrames are created out of
2186 // order (https://crbug.com/478792). Instead, target second frame by name.
2187 EXPECT_TRUE(ExecuteScript(
2188 root->child_at(0)->current_frame_host(),
2189 "window.domAutomationController.send("
2190 " parent.frames['frame2'].location.href = 'data:text/html,foo');"));
2191 console_delegate->Wait();
2193 std::string frame_origin =
2194 root->child_at(1)->current_replication_state().origin.string();
2195 EXPECT_EQ(frame_origin + "/", frame_url.GetOrigin().spec());
2196 EXPECT_TRUE(
2197 MatchPattern(console_delegate->message(), "*" + frame_origin + "*"))
2198 << "Error message does not contain the frame's latest origin ("
2199 << frame_origin << ")";
2202 // Ensure that navigating subframes in --site-per-process mode properly fires
2203 // the DidStopLoading event on WebContentsObserver.
2204 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteDidStopLoading) {
2205 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
2206 NavigateToURL(shell(), main_url);
2208 // It is safe to obtain the root frame tree node here, as it doesn't change.
2209 FrameTreeNode* root =
2210 static_cast<WebContentsImpl*>(shell()->web_contents())->
2211 GetFrameTree()->root();
2213 TestNavigationObserver observer(shell()->web_contents());
2215 // Load same-site page into iframe.
2216 FrameTreeNode* child = root->child_at(0);
2217 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
2218 NavigateFrameToURL(child, http_url);
2219 EXPECT_EQ(http_url, observer.last_navigation_url());
2220 EXPECT_TRUE(observer.last_navigation_succeeded());
2222 // Load cross-site page into iframe.
2223 TestNavigationObserver nav_observer(shell()->web_contents(), 1);
2224 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
2225 NavigationController::LoadURLParams params(url);
2226 params.transition_type = ui::PAGE_TRANSITION_LINK;
2227 params.frame_tree_node_id = child->frame_tree_node_id();
2228 child->navigator()->GetController()->LoadURLWithParams(params);
2229 nav_observer.Wait();
2231 // Verify that the navigation succeeded and the expected URL was loaded.
2232 EXPECT_TRUE(observer.last_navigation_succeeded());
2233 EXPECT_EQ(url, observer.last_navigation_url());
2236 // Ensure that the renderer does not crash when navigating a frame that has a
2237 // sibling RemoteFrame. See https://crbug.com/426953.
2238 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2239 NavigateWithSiblingRemoteFrame) {
2240 GURL main_url(
2241 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
2242 NavigateToURL(shell(), main_url);
2244 // It is safe to obtain the root frame tree node here, as it doesn't change.
2245 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2246 ->GetFrameTree()
2247 ->root();
2248 TestNavigationObserver observer(shell()->web_contents());
2250 // Make sure the first frame is out of process.
2251 ASSERT_EQ(2U, root->child_count());
2252 FrameTreeNode* node2 = root->child_at(0);
2253 EXPECT_NE(root->current_frame_host()->GetSiteInstance(),
2254 node2->current_frame_host()->GetSiteInstance());
2256 // Make sure the second frame is in the parent's process.
2257 FrameTreeNode* node3 = root->child_at(1);
2258 EXPECT_EQ(root->current_frame_host()->GetSiteInstance(),
2259 node3->current_frame_host()->GetSiteInstance());
2261 // Navigate the second iframe (node3) to a URL in its own process.
2262 GURL title_url = embedded_test_server()->GetURL("/title2.html");
2263 NavigateFrameToURL(node3, title_url);
2264 EXPECT_TRUE(observer.last_navigation_succeeded());
2265 EXPECT_EQ(title_url, observer.last_navigation_url());
2266 EXPECT_EQ(root->current_frame_host()->GetSiteInstance(),
2267 node3->current_frame_host()->GetSiteInstance());
2268 EXPECT_TRUE(node3->current_frame_host()->IsRenderFrameLive());
2271 // Verify that load events for iframe elements work when the child frame is
2272 // out-of-process. In such cases, the load event is forwarded from the child
2273 // frame to the parent frame via the browser process.
2274 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, LoadEventForwarding) {
2275 // Load a page with a cross-site frame. The parent page has an onload
2276 // handler in the iframe element that appends "LOADED" to the document title.
2278 GURL main_url(
2279 embedded_test_server()->GetURL("/frame_with_load_event.html"));
2280 base::string16 expected_title(base::UTF8ToUTF16("LOADED"));
2281 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
2282 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2283 EXPECT_EQ(title_watcher.WaitAndGetTitle(), expected_title);
2286 // It is safe to obtain the root frame tree node here, as it doesn't change.
2287 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2288 ->GetFrameTree()
2289 ->root();
2291 // Load another cross-site page into the iframe and check that the load event
2292 // is fired.
2294 GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
2295 base::string16 expected_title(base::UTF8ToUTF16("LOADEDLOADED"));
2296 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
2297 TestNavigationObserver observer(shell()->web_contents());
2298 NavigateFrameToURL(root->child_at(0), foo_url);
2299 EXPECT_TRUE(observer.last_navigation_succeeded());
2300 EXPECT_EQ(foo_url, observer.last_navigation_url());
2301 EXPECT_EQ(title_watcher.WaitAndGetTitle(), expected_title);
2305 // Check that postMessage can be routed between cross-site iframes.
2306 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SubframePostMessage) {
2307 GURL main_url(embedded_test_server()->GetURL(
2308 "/frame_tree/page_with_post_message_frames.html"));
2309 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2311 // It is safe to obtain the root frame tree node here, as it doesn't change.
2312 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2313 ->GetFrameTree()
2314 ->root();
2316 TestNavigationObserver observer(shell()->web_contents());
2317 ASSERT_EQ(2U, root->child_count());
2319 // Verify the frames start at correct URLs. First frame should be
2320 // same-site; second frame should be cross-site.
2321 GURL same_site_url(embedded_test_server()->GetURL("/post_message.html"));
2322 EXPECT_EQ(same_site_url, root->child_at(0)->current_url());
2323 GURL foo_url(embedded_test_server()->GetURL("foo.com",
2324 "/post_message.html"));
2325 EXPECT_EQ(foo_url, root->child_at(1)->current_url());
2326 EXPECT_NE(root->child_at(0)->current_frame_host()->GetSiteInstance(),
2327 root->child_at(1)->current_frame_host()->GetSiteInstance());
2329 // Send a message from first, same-site frame to second, cross-site frame.
2330 // Expect the second frame to reply back to the first frame.
2331 PostMessageAndWaitForReply(root->child_at(0),
2332 "postToSibling('subframe-msg','subframe2')",
2333 "\"done-subframe1\"");
2335 // Send a postMessage from second, cross-site frame to its parent. Expect
2336 // parent to send a reply to the frame.
2337 base::string16 expected_title(base::ASCIIToUTF16("subframe-msg"));
2338 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
2339 PostMessageAndWaitForReply(root->child_at(1), "postToParent('subframe-msg')",
2340 "\"done-subframe2\"");
2341 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
2343 // Verify the total number of received messages for each subframe. First
2344 // frame should have one message (reply from second frame), and second frame
2345 // should have two messages (message from first frame and reply from parent).
2346 int subframe1_received_messages = 0;
2347 int subframe2_received_messages = 0;
2348 EXPECT_TRUE(ExecuteScriptAndExtractInt(
2349 root->child_at(0)->current_frame_host(),
2350 "window.domAutomationController.send(window.receivedMessages);",
2351 &subframe1_received_messages));
2352 EXPECT_EQ(1, subframe1_received_messages);
2353 EXPECT_TRUE(ExecuteScriptAndExtractInt(
2354 root->child_at(1)->current_frame_host(),
2355 "window.domAutomationController.send(window.receivedMessages);",
2356 &subframe2_received_messages));
2357 EXPECT_EQ(2, subframe2_received_messages);
2360 // Check that parent.frames[num] references correct sibling frames when the
2361 // parent is remote. See https://crbug.com/478792.
2362 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, IndexedFrameAccess) {
2363 // Start on a page with three same-site subframes.
2364 GURL main_url(
2365 embedded_test_server()->GetURL("a.com", "/frame_tree/top.html"));
2366 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2368 // It is safe to obtain the root frame tree node here, as it doesn't change.
2369 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2370 ->GetFrameTree()
2371 ->root();
2372 ASSERT_EQ(3U, root->child_count());
2373 FrameTreeNode* child0 = root->child_at(0);
2374 FrameTreeNode* child1 = root->child_at(1);
2375 FrameTreeNode* child2 = root->child_at(2);
2377 // Send each of the frames to a different site. Each new renderer will first
2378 // create proxies for the parent and two sibling subframes and then create
2379 // and insert the new RenderFrame into the frame tree.
2380 GURL b_url(embedded_test_server()->GetURL("b.com", "/post_message.html"));
2381 GURL c_url(embedded_test_server()->GetURL("c.com", "/post_message.html"));
2382 GURL d_url(embedded_test_server()->GetURL("d.com", "/post_message.html"));
2383 NavigateFrameToURL(child0, b_url);
2384 // TODO(alexmos): The calls to WaitForRenderFrameReady can be removed once
2385 // TestFrameNavigationObserver is fixed to use DidFinishLoad.
2386 EXPECT_TRUE(WaitForRenderFrameReady(child0->current_frame_host()));
2387 NavigateFrameToURL(child1, c_url);
2388 EXPECT_TRUE(WaitForRenderFrameReady(child1->current_frame_host()));
2389 NavigateFrameToURL(child2, d_url);
2390 EXPECT_TRUE(WaitForRenderFrameReady(child2->current_frame_host()));
2392 EXPECT_EQ(
2393 " Site A ------------ proxies for B C D\n"
2394 " |--Site B ------- proxies for A C D\n"
2395 " |--Site C ------- proxies for A B D\n"
2396 " +--Site D ------- proxies for A B C\n"
2397 "Where A = http://a.com/\n"
2398 " B = http://b.com/\n"
2399 " C = http://c.com/\n"
2400 " D = http://d.com/",
2401 DepictFrameTree(root));
2403 // Check that each subframe sees itself at correct index in parent.frames.
2404 bool success = false;
2405 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2406 child0->current_frame_host(),
2407 "window.domAutomationController.send(window === parent.frames[0]);",
2408 &success));
2409 EXPECT_TRUE(success);
2411 success = false;
2412 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2413 child1->current_frame_host(),
2414 "window.domAutomationController.send(window === parent.frames[1]);",
2415 &success));
2416 EXPECT_TRUE(success);
2418 success = false;
2419 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2420 child2->current_frame_host(),
2421 "window.domAutomationController.send(window === parent.frames[2]);",
2422 &success));
2423 EXPECT_TRUE(success);
2425 // Send a postMessage from B to parent.frames[1], which should go to C, and
2426 // wait for reply.
2427 PostMessageAndWaitForReply(child0, "postToSibling('subframe-msg', 1)",
2428 "\"done-1-1-name\"");
2430 // Send a postMessage from C to parent.frames[2], which should go to D, and
2431 // wait for reply.
2432 PostMessageAndWaitForReply(child1, "postToSibling('subframe-msg', 2)",
2433 "\"done-1-2-name\"");
2435 // Verify the total number of received messages for each subframe.
2436 int child0_received_messages = 0;
2437 EXPECT_TRUE(ExecuteScriptAndExtractInt(
2438 child0->current_frame_host(),
2439 "window.domAutomationController.send(window.receivedMessages);",
2440 &child0_received_messages));
2441 EXPECT_EQ(1, child0_received_messages);
2443 int child1_received_messages = 0;
2444 EXPECT_TRUE(ExecuteScriptAndExtractInt(
2445 child1->current_frame_host(),
2446 "window.domAutomationController.send(window.receivedMessages);",
2447 &child1_received_messages));
2448 EXPECT_EQ(2, child1_received_messages);
2450 int child2_received_messages = 0;
2451 EXPECT_TRUE(ExecuteScriptAndExtractInt(
2452 child2->current_frame_host(),
2453 "window.domAutomationController.send(window.receivedMessages);",
2454 &child2_received_messages));
2455 EXPECT_EQ(1, child2_received_messages);
2458 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, RFPHDestruction) {
2459 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
2460 NavigateToURL(shell(), main_url);
2462 // It is safe to obtain the root frame tree node here, as it doesn't change.
2463 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2464 ->GetFrameTree()
2465 ->root();
2467 TestNavigationObserver observer(shell()->web_contents());
2469 // Load cross-site page into iframe.
2470 FrameTreeNode* child = root->child_at(0);
2471 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
2472 NavigateFrameToURL(root->child_at(0), url);
2473 EXPECT_TRUE(observer.last_navigation_succeeded());
2474 EXPECT_EQ(url, observer.last_navigation_url());
2475 EXPECT_EQ(
2476 " Site A ------------ proxies for B\n"
2477 " |--Site B ------- proxies for A\n"
2478 " +--Site A ------- proxies for B\n"
2479 " |--Site A -- proxies for B\n"
2480 " +--Site A -- proxies for B\n"
2481 " +--Site A -- proxies for B\n"
2482 "Where A = http://127.0.0.1/\n"
2483 " B = http://foo.com/",
2484 DepictFrameTree(root));
2486 // Load another cross-site page.
2487 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
2488 NavigateIframeToURL(shell()->web_contents(), "test", url);
2489 EXPECT_TRUE(observer.last_navigation_succeeded());
2490 EXPECT_EQ(url, observer.last_navigation_url());
2491 EXPECT_EQ(
2492 " Site A ------------ proxies for C\n"
2493 " |--Site C ------- proxies for A\n"
2494 " +--Site A ------- proxies for C\n"
2495 " |--Site A -- proxies for C\n"
2496 " +--Site A -- proxies for C\n"
2497 " +--Site A -- proxies for C\n"
2498 "Where A = http://127.0.0.1/\n"
2499 " C = http://bar.com/",
2500 DepictFrameTree(root));
2502 // Navigate back to the parent's origin.
2503 url = embedded_test_server()->GetURL("/title1.html");
2504 NavigateFrameToURL(child, url);
2505 EXPECT_EQ(url, observer.last_navigation_url());
2506 EXPECT_TRUE(observer.last_navigation_succeeded());
2507 EXPECT_EQ(
2508 " Site A\n"
2509 " |--Site A\n"
2510 " +--Site A\n"
2511 " |--Site A\n"
2512 " +--Site A\n"
2513 " +--Site A\n"
2514 "Where A = http://127.0.0.1/",
2515 DepictFrameTree(root));
2518 } // namespace content