Permission messages: Add a bunch of missing combinations/suppressions.
[chromium-blink-merge.git] / content / browser / site_per_process_browsertest.cc
blob050a5e5e35b20025d14a09053c123a4c2f6827eb
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/site_per_process_browsertest.h"
7 #include <algorithm>
8 #include <vector>
10 #include "base/command_line.h"
11 #include "base/location.h"
12 #include "base/single_thread_task_runner.h"
13 #include "base/strings/pattern.h"
14 #include "base/strings/stringprintf.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/thread_task_runner_handle.h"
17 #include "content/browser/frame_host/cross_process_frame_connector.h"
18 #include "content/browser/frame_host/frame_tree.h"
19 #include "content/browser/frame_host/navigator.h"
20 #include "content/browser/frame_host/render_frame_proxy_host.h"
21 #include "content/browser/frame_host/render_widget_host_view_child_frame.h"
22 #include "content/browser/gpu/compositor_util.h"
23 #include "content/browser/renderer_host/render_view_host_impl.h"
24 #include "content/browser/renderer_host/render_widget_host_input_event_router.h"
25 #include "content/browser/web_contents/web_contents_impl.h"
26 #include "content/common/frame_messages.h"
27 #include "content/public/browser/notification_observer.h"
28 #include "content/public/browser/notification_service.h"
29 #include "content/public/browser/notification_types.h"
30 #include "content/public/common/content_switches.h"
31 #include "content/public/test/browser_test_utils.h"
32 #include "content/public/test/content_browser_test_utils.h"
33 #include "content/public/test/test_navigation_observer.h"
34 #include "content/public/test/test_utils.h"
35 #include "content/shell/browser/shell.h"
36 #include "content/test/content_browser_test_utils_internal.h"
37 #include "content/test/test_frame_navigation_observer.h"
38 #include "ipc/ipc_security_test_util.h"
39 #include "net/dns/mock_host_resolver.h"
40 #include "net/test/embedded_test_server/embedded_test_server.h"
41 #include "third_party/WebKit/public/web/WebInputEvent.h"
42 #include "third_party/WebKit/public/web/WebSandboxFlags.h"
44 namespace content {
46 namespace {
48 // Helper function to send a postMessage and wait for a reply message. The
49 // |post_message_script| is executed on the |sender_ftn| frame, and the sender
50 // frame is expected to post |reply_status| from the DOMAutomationController
51 // when it receives a reply.
52 void PostMessageAndWaitForReply(FrameTreeNode* sender_ftn,
53 const std::string& post_message_script,
54 const std::string& reply_status) {
55 // Subtle: msg_queue needs to be declared before the ExecuteScript below, or
56 // else it might miss the message of interest. See https://crbug.com/518729.
57 DOMMessageQueue msg_queue;
59 bool success = false;
60 EXPECT_TRUE(ExecuteScriptAndExtractBool(
61 sender_ftn->current_frame_host(),
62 "window.domAutomationController.send(" + post_message_script + ");",
63 &success));
64 EXPECT_TRUE(success);
66 std::string status;
67 while (msg_queue.WaitForMessage(&status)) {
68 if (status == reply_status)
69 break;
73 // Helper function to extract and return "window.receivedMessages" from the
74 // |sender_ftn| frame. This variable is used in post_message.html to count the
75 // number of messages received via postMessage by the current window.
76 int GetReceivedMessages(FrameTreeNode* ftn) {
77 int received_messages = 0;
78 EXPECT_TRUE(ExecuteScriptAndExtractInt(
79 ftn->current_frame_host(),
80 "window.domAutomationController.send(window.receivedMessages);",
81 &received_messages));
82 return received_messages;
85 // Helper function to perform a window.open from the |caller_frame| targeting a
86 // frame with the specified name.
87 void NavigateNamedFrame(const ToRenderFrameHost& caller_frame,
88 const GURL& url,
89 const std::string& name) {
90 bool success = false;
91 EXPECT_TRUE(ExecuteScriptAndExtractBool(
92 caller_frame,
93 "window.domAutomationController.send("
94 " !!window.open('" + url.spec() + "', '" + name + "'));",
95 &success));
96 EXPECT_TRUE(success);
99 class RedirectNotificationObserver : public NotificationObserver {
100 public:
101 // Register to listen for notifications of the given type from either a
102 // specific source, or from all sources if |source| is
103 // NotificationService::AllSources().
104 RedirectNotificationObserver(int notification_type,
105 const NotificationSource& source);
106 ~RedirectNotificationObserver() override;
108 // Wait until the specified notification occurs. If the notification was
109 // emitted between the construction of this object and this call then it
110 // returns immediately.
111 void Wait();
113 // Returns NotificationService::AllSources() if we haven't observed a
114 // notification yet.
115 const NotificationSource& source() const {
116 return source_;
119 const NotificationDetails& details() const {
120 return details_;
123 // NotificationObserver:
124 void Observe(int type,
125 const NotificationSource& source,
126 const NotificationDetails& details) override;
128 private:
129 bool seen_;
130 bool seen_twice_;
131 bool running_;
132 NotificationRegistrar registrar_;
134 NotificationSource source_;
135 NotificationDetails details_;
136 scoped_refptr<MessageLoopRunner> message_loop_runner_;
138 DISALLOW_COPY_AND_ASSIGN(RedirectNotificationObserver);
141 RedirectNotificationObserver::RedirectNotificationObserver(
142 int notification_type,
143 const NotificationSource& source)
144 : seen_(false),
145 running_(false),
146 source_(NotificationService::AllSources()) {
147 registrar_.Add(this, notification_type, source);
150 RedirectNotificationObserver::~RedirectNotificationObserver() {}
152 void RedirectNotificationObserver::Wait() {
153 if (seen_ && seen_twice_)
154 return;
156 running_ = true;
157 message_loop_runner_ = new MessageLoopRunner;
158 message_loop_runner_->Run();
159 EXPECT_TRUE(seen_);
162 void RedirectNotificationObserver::Observe(
163 int type,
164 const NotificationSource& source,
165 const NotificationDetails& details) {
166 source_ = source;
167 details_ = details;
168 seen_twice_ = seen_;
169 seen_ = true;
170 if (!running_)
171 return;
173 message_loop_runner_->Quit();
174 running_ = false;
177 // This observer keeps track of the number of created RenderFrameHosts. Tests
178 // can use this to ensure that a certain number of child frames has been
179 // created after navigating.
180 class RenderFrameHostCreatedObserver : public WebContentsObserver {
181 public:
182 RenderFrameHostCreatedObserver(WebContents* web_contents,
183 int expected_frame_count)
184 : WebContentsObserver(web_contents),
185 expected_frame_count_(expected_frame_count),
186 frames_created_(0),
187 message_loop_runner_(new MessageLoopRunner) {}
189 ~RenderFrameHostCreatedObserver() override;
191 // Runs a nested message loop and blocks until the expected number of
192 // RenderFrameHosts is created.
193 void Wait();
195 private:
196 // WebContentsObserver
197 void RenderFrameCreated(RenderFrameHost* render_frame_host) override;
199 // The number of RenderFrameHosts to wait for.
200 int expected_frame_count_;
202 // The number of RenderFrameHosts that have been created.
203 int frames_created_;
205 // The MessageLoopRunner used to spin the message loop.
206 scoped_refptr<MessageLoopRunner> message_loop_runner_;
208 DISALLOW_COPY_AND_ASSIGN(RenderFrameHostCreatedObserver);
211 RenderFrameHostCreatedObserver::~RenderFrameHostCreatedObserver() {
214 void RenderFrameHostCreatedObserver::Wait() {
215 message_loop_runner_->Run();
218 void RenderFrameHostCreatedObserver::RenderFrameCreated(
219 RenderFrameHost* render_frame_host) {
220 frames_created_++;
221 if (frames_created_ == expected_frame_count_) {
222 message_loop_runner_->Quit();
226 // A WebContentsDelegate that catches messages sent to the console.
227 class ConsoleObserverDelegate : public WebContentsDelegate {
228 public:
229 ConsoleObserverDelegate(WebContents* web_contents, const std::string& filter)
230 : web_contents_(web_contents),
231 filter_(filter),
232 message_(""),
233 message_loop_runner_(new MessageLoopRunner) {}
235 ~ConsoleObserverDelegate() override {}
237 bool AddMessageToConsole(WebContents* source,
238 int32 level,
239 const base::string16& message,
240 int32 line_no,
241 const base::string16& source_id) override;
243 std::string message() { return message_; }
245 void Wait();
247 private:
248 WebContents* web_contents_;
249 std::string filter_;
250 std::string message_;
252 // The MessageLoopRunner used to spin the message loop.
253 scoped_refptr<MessageLoopRunner> message_loop_runner_;
255 DISALLOW_COPY_AND_ASSIGN(ConsoleObserverDelegate);
258 void ConsoleObserverDelegate::Wait() {
259 message_loop_runner_->Run();
262 bool ConsoleObserverDelegate::AddMessageToConsole(
263 WebContents* source,
264 int32 level,
265 const base::string16& message,
266 int32 line_no,
267 const base::string16& source_id) {
268 DCHECK(source == web_contents_);
270 std::string ascii_message = base::UTF16ToASCII(message);
271 if (base::MatchPattern(ascii_message, filter_)) {
272 message_ = ascii_message;
273 message_loop_runner_->Quit();
275 return false;
278 } // namespace
281 // SitePerProcessBrowserTest
284 SitePerProcessBrowserTest::SitePerProcessBrowserTest() {
287 std::string SitePerProcessBrowserTest::DepictFrameTree(FrameTreeNode* node) {
288 return visualizer_.DepictFrameTree(node);
291 void SitePerProcessBrowserTest::SetUpCommandLine(
292 base::CommandLine* command_line) {
293 IsolateAllSitesForTesting(command_line);
296 void SitePerProcessBrowserTest::SetUpOnMainThread() {
297 host_resolver()->AddRule("*", "127.0.0.1");
298 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
299 SetupCrossSiteRedirector(embedded_test_server());
302 // Ensure that navigating subframes in --site-per-process mode works and the
303 // correct documents are committed.
304 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframe) {
305 GURL main_url(embedded_test_server()->GetURL(
306 "a.com", "/cross_site_iframe_factory.html?a(a,a(a,a(a)))"));
307 NavigateToURL(shell(), main_url);
309 // It is safe to obtain the root frame tree node here, as it doesn't change.
310 FrameTreeNode* root =
311 static_cast<WebContentsImpl*>(shell()->web_contents())->
312 GetFrameTree()->root();
314 TestNavigationObserver observer(shell()->web_contents());
316 // Load same-site page into iframe.
317 FrameTreeNode* child = root->child_at(0);
318 GURL http_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
319 NavigateFrameToURL(child, http_url);
320 EXPECT_EQ(http_url, observer.last_navigation_url());
321 EXPECT_TRUE(observer.last_navigation_succeeded());
323 // There should be only one RenderWidgetHost when there are no
324 // cross-process iframes.
325 std::set<RenderWidgetHostView*> views_set =
326 static_cast<WebContentsImpl*>(shell()->web_contents())
327 ->GetRenderWidgetHostViewsInTree();
328 EXPECT_EQ(1U, views_set.size());
331 EXPECT_EQ(
332 " Site A\n"
333 " |--Site A\n"
334 " +--Site A\n"
335 " |--Site A\n"
336 " +--Site A\n"
337 " +--Site A\n"
338 "Where A = http://a.com/",
339 DepictFrameTree(root));
341 // Load cross-site page into iframe.
342 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
343 NavigateFrameToURL(root->child_at(0), url);
344 // Verify that the navigation succeeded and the expected URL was loaded.
345 EXPECT_TRUE(observer.last_navigation_succeeded());
346 EXPECT_EQ(url, observer.last_navigation_url());
348 // Ensure that we have created a new process for the subframe.
349 ASSERT_EQ(2U, root->child_count());
350 SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
351 RenderViewHost* rvh = child->current_frame_host()->render_view_host();
352 RenderProcessHost* rph = child->current_frame_host()->GetProcess();
353 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh);
354 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
355 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), rph);
357 // There should be now two RenderWidgetHosts, one for each process
358 // rendering a frame.
359 std::set<RenderWidgetHostView*> views_set =
360 static_cast<WebContentsImpl*>(shell()->web_contents())
361 ->GetRenderWidgetHostViewsInTree();
362 EXPECT_EQ(2U, views_set.size());
364 RenderFrameProxyHost* proxy_to_parent =
365 child->render_manager()->GetProxyToParent();
366 EXPECT_TRUE(proxy_to_parent);
367 EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
368 // The out-of-process iframe should have its own RenderWidgetHost,
369 // independent of any RenderViewHost.
370 EXPECT_NE(
371 rvh->GetView(),
372 proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
373 EXPECT_TRUE(child->current_frame_host()->GetRenderWidgetHost());
375 EXPECT_EQ(
376 " Site A ------------ proxies for B\n"
377 " |--Site B ------- proxies for A\n"
378 " +--Site A ------- proxies for B\n"
379 " |--Site A -- proxies for B\n"
380 " +--Site A -- proxies for B\n"
381 " +--Site A -- proxies for B\n"
382 "Where A = http://a.com/\n"
383 " B = http://foo.com/",
384 DepictFrameTree(root));
386 // Load another cross-site page into the same iframe.
387 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
388 NavigateFrameToURL(root->child_at(0), url);
389 EXPECT_TRUE(observer.last_navigation_succeeded());
390 EXPECT_EQ(url, observer.last_navigation_url());
392 // Check again that a new process is created and is different from the
393 // top level one and the previous one.
394 ASSERT_EQ(2U, root->child_count());
395 child = root->child_at(0);
396 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(),
397 child->current_frame_host()->render_view_host());
398 EXPECT_NE(rvh, child->current_frame_host()->render_view_host());
399 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
400 child->current_frame_host()->GetSiteInstance());
401 EXPECT_NE(site_instance,
402 child->current_frame_host()->GetSiteInstance());
403 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(),
404 child->current_frame_host()->GetProcess());
405 EXPECT_NE(rph, child->current_frame_host()->GetProcess());
407 std::set<RenderWidgetHostView*> views_set =
408 static_cast<WebContentsImpl*>(shell()->web_contents())
409 ->GetRenderWidgetHostViewsInTree();
410 EXPECT_EQ(2U, views_set.size());
412 EXPECT_EQ(proxy_to_parent, child->render_manager()->GetProxyToParent());
413 EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
414 EXPECT_NE(
415 child->current_frame_host()->render_view_host()->GetView(),
416 proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
417 EXPECT_TRUE(child->current_frame_host()->GetRenderWidgetHost());
419 EXPECT_EQ(
420 " Site A ------------ proxies for C\n"
421 " |--Site C ------- proxies for A\n"
422 " +--Site A ------- proxies for C\n"
423 " |--Site A -- proxies for C\n"
424 " +--Site A -- proxies for C\n"
425 " +--Site A -- proxies for C\n"
426 "Where A = http://a.com/\n"
427 " C = http://bar.com/",
428 DepictFrameTree(root));
431 class RenderWidgetHostMouseEventMonitor {
432 public:
433 RenderWidgetHostMouseEventMonitor(RenderWidgetHost* host)
434 : host_(host), event_received(false) {
435 host_->AddMouseEventCallback(
436 base::Bind(&RenderWidgetHostMouseEventMonitor::MouseEventCallback,
437 base::Unretained(this)));
439 ~RenderWidgetHostMouseEventMonitor() {
440 host_->RemoveMouseEventCallback(
441 base::Bind(&RenderWidgetHostMouseEventMonitor::MouseEventCallback,
442 base::Unretained(this)));
444 bool EventWasReceived() { return event_received; }
445 void ResetEventReceived() { event_received = false; }
447 private:
448 bool MouseEventCallback(const blink::WebMouseEvent& /* event */) {
449 event_received = true;
450 return false;
452 RenderWidgetHost* host_;
453 bool event_received;
456 // Test that mouse events are being routed to the correct RenderWidgetHostView
457 // based on coordinates.
458 #if defined(OS_ANDROID) || defined(THREAD_SANITIZER)
459 // Browser process hit testing is not implemented on Android.
460 // https://crbug.com/491334
461 // Test fails under TSAN, see https://crbug.com/527618
462 #define MAYBE_SurfaceHitTestTest DISABLED_SurfaceHitTestTest
463 #else
464 #define MAYBE_SurfaceHitTestTest SurfaceHitTestTest
465 #endif
466 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_SurfaceHitTestTest) {
467 if (!UseSurfacesEnabled())
468 return;
470 GURL main_url(embedded_test_server()->GetURL(
471 "/frame_tree/page_with_positioned_frame.html"));
472 NavigateToURL(shell(), main_url);
474 // It is safe to obtain the root frame tree node here, as it doesn't change.
475 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
476 ->GetFrameTree()
477 ->root();
478 ASSERT_EQ(1U, root->child_count());
480 FrameTreeNode* child_node = root->child_at(0);
481 GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
482 EXPECT_EQ(site_url, child_node->current_url());
483 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
484 child_node->current_frame_host()->GetSiteInstance());
486 // Create listeners for mouse events.
487 RenderWidgetHostMouseEventMonitor main_frame_monitor(
488 root->current_frame_host()->GetRenderWidgetHost());
489 RenderWidgetHostMouseEventMonitor child_frame_monitor(
490 child_node->current_frame_host()->GetRenderWidgetHost());
492 RenderWidgetHostInputEventRouter* router =
493 static_cast<WebContentsImpl*>(shell()->web_contents())
494 ->GetInputEventRouter();
496 RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
497 root->current_frame_host()->GetRenderWidgetHost()->GetView());
498 RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
499 child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
501 // We need to wait for a compositor frame from the child frame, at which
502 // point its surface will be created.
503 while (rwhv_child->RendererFrameNumber() <= 0) {
504 // TODO(lazyboy): Find a better way to avoid sleeping like this. See
505 // http://crbug.com/405282 for details.
506 base::RunLoop run_loop;
507 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
508 FROM_HERE, run_loop.QuitClosure(),
509 base::TimeDelta::FromMilliseconds(10));
510 run_loop.Run();
513 uint32_t cur_render_frame_number = root_view->RendererFrameNumber();
515 // Target input event to child frame.
516 blink::WebMouseEvent child_event;
517 child_event.type = blink::WebInputEvent::MouseDown;
518 child_event.button = blink::WebPointerProperties::ButtonLeft;
519 child_event.x = 75;
520 child_event.y = 75;
521 child_event.clickCount = 1;
522 router->RouteMouseEvent(root_view, &child_event);
524 if (!child_frame_monitor.EventWasReceived()) {
525 main_frame_monitor.ResetEventReceived();
526 // This is working around a big synchronization problem. It is very
527 // difficult to know if we have received a compositor frame from the
528 // main frame renderer *after* it received the child frame's surface
529 // ID. Hit testing won't work until this happens. So if the hit test
530 // fails then we wait for another frame to arrive and try again.
531 // TODO(kenrb): We need a better way to do all of this, possibly coming
532 // from http://crbug.com/405282.
533 while (root_view->RendererFrameNumber() <= cur_render_frame_number) {
534 base::RunLoop run_loop;
535 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
536 FROM_HERE, run_loop.QuitClosure(),
537 base::TimeDelta::FromMilliseconds(10));
538 run_loop.Run();
540 router->RouteMouseEvent(root_view, &child_event);
543 EXPECT_TRUE(child_frame_monitor.EventWasReceived());
544 EXPECT_FALSE(main_frame_monitor.EventWasReceived());
546 child_frame_monitor.ResetEventReceived();
547 main_frame_monitor.ResetEventReceived();
549 // Target input event to main frame.
550 blink::WebMouseEvent main_event;
551 main_event.type = blink::WebInputEvent::MouseDown;
552 main_event.button = blink::WebPointerProperties::ButtonLeft;
553 main_event.x = 1;
554 main_event.y = 1;
555 main_event.clickCount = 1;
556 // Ladies and gentlemen, THIS is the main_event!
557 router->RouteMouseEvent(root_view, &main_event);
559 EXPECT_FALSE(child_frame_monitor.EventWasReceived());
560 EXPECT_TRUE(main_frame_monitor.EventWasReceived());
563 // Tests OOPIF rendering by checking that the RWH of the iframe generates
564 // OnSwapCompositorFrame message.
565 #if defined(OS_ANDROID)
566 // http://crbug.com/471850
567 #define MAYBE_CompositorFrameSwapped DISABLED_CompositorFrameSwapped
568 #else
569 #define MAYBE_CompositorFrameSwapped CompositorFrameSwapped
570 #endif
571 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
572 MAYBE_CompositorFrameSwapped) {
573 GURL main_url(embedded_test_server()->GetURL(
574 "a.com", "/cross_site_iframe_factory.html?a(baz)"));
575 NavigateToURL(shell(), main_url);
577 // It is safe to obtain the root frame tree node here, as it doesn't change.
578 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
579 ->GetFrameTree()
580 ->root();
581 ASSERT_EQ(1U, root->child_count());
583 FrameTreeNode* child_node = root->child_at(0);
584 GURL site_url(embedded_test_server()->GetURL(
585 "baz.com", "/cross_site_iframe_factory.html?baz()"));
586 EXPECT_EQ(site_url, child_node->current_url());
587 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
588 child_node->current_frame_host()->GetSiteInstance());
589 RenderWidgetHostViewBase* rwhv_base = static_cast<RenderWidgetHostViewBase*>(
590 child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
592 // Wait for OnSwapCompositorFrame message.
593 while (rwhv_base->RendererFrameNumber() <= 0) {
594 // TODO(lazyboy): Find a better way to avoid sleeping like this. See
595 // http://crbug.com/405282 for details.
596 base::RunLoop run_loop;
597 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
598 FROM_HERE, run_loop.QuitClosure(),
599 base::TimeDelta::FromMilliseconds(10));
600 run_loop.Run();
604 // Ensure that OOPIFs are deleted after navigating to a new main frame.
605 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CleanupCrossSiteIframe) {
606 GURL main_url(embedded_test_server()->GetURL(
607 "a.com", "/cross_site_iframe_factory.html?a(a,a(a,a(a)))"));
608 NavigateToURL(shell(), main_url);
610 // It is safe to obtain the root frame tree node here, as it doesn't change.
611 FrameTreeNode* root =
612 static_cast<WebContentsImpl*>(shell()->web_contents())->
613 GetFrameTree()->root();
615 TestNavigationObserver observer(shell()->web_contents());
617 // Load a cross-site page into both iframes.
618 GURL foo_url = embedded_test_server()->GetURL("foo.com", "/title2.html");
619 NavigateFrameToURL(root->child_at(0), foo_url);
620 EXPECT_TRUE(observer.last_navigation_succeeded());
621 EXPECT_EQ(foo_url, observer.last_navigation_url());
622 NavigateFrameToURL(root->child_at(1), foo_url);
623 EXPECT_TRUE(observer.last_navigation_succeeded());
624 EXPECT_EQ(foo_url, observer.last_navigation_url());
626 // Ensure that we have created a new process for the subframes.
627 EXPECT_EQ(
628 " Site A ------------ proxies for B\n"
629 " |--Site B ------- proxies for A\n"
630 " +--Site B ------- proxies for A\n"
631 "Where A = http://a.com/\n"
632 " B = http://foo.com/",
633 DepictFrameTree(root));
635 int subframe_process_id = root->child_at(0)
636 ->current_frame_host()
637 ->GetSiteInstance()
638 ->GetProcess()
639 ->GetID();
640 int subframe_rvh_id = root->child_at(0)
641 ->current_frame_host()
642 ->render_view_host()
643 ->GetRoutingID();
644 EXPECT_TRUE(RenderViewHost::FromID(subframe_process_id, subframe_rvh_id));
646 // Use Javascript in the parent to remove one of the frames and ensure that
647 // the subframe goes away.
648 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
649 "document.body.removeChild("
650 "document.querySelectorAll('iframe')[0])"));
651 ASSERT_EQ(1U, root->child_count());
653 // Load a new same-site page in the top-level frame and ensure the other
654 // subframe goes away.
655 GURL new_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
656 NavigateToURL(shell(), new_url);
657 ASSERT_EQ(0U, root->child_count());
659 // Ensure the RVH for the subframe gets cleaned up when the frame goes away.
660 EXPECT_FALSE(RenderViewHost::FromID(subframe_process_id, subframe_rvh_id));
663 // Ensure that root frames cannot be detached.
664 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, RestrictFrameDetach) {
665 GURL main_url(embedded_test_server()->GetURL(
666 "a.com", "/cross_site_iframe_factory.html?a(a,a(a,a(a)))"));
667 NavigateToURL(shell(), main_url);
669 // It is safe to obtain the root frame tree node here, as it doesn't change.
670 FrameTreeNode* root =
671 static_cast<WebContentsImpl*>(shell()->web_contents())->
672 GetFrameTree()->root();
674 TestNavigationObserver observer(shell()->web_contents());
676 // Load cross-site pages into both iframes.
677 GURL foo_url = embedded_test_server()->GetURL("foo.com", "/title2.html");
678 NavigateFrameToURL(root->child_at(0), foo_url);
679 EXPECT_TRUE(observer.last_navigation_succeeded());
680 EXPECT_EQ(foo_url, observer.last_navigation_url());
681 GURL bar_url = embedded_test_server()->GetURL("bar.com", "/title2.html");
682 NavigateFrameToURL(root->child_at(1), bar_url);
683 EXPECT_TRUE(observer.last_navigation_succeeded());
684 EXPECT_EQ(bar_url, observer.last_navigation_url());
686 // Ensure that we have created new processes for the subframes.
687 ASSERT_EQ(2U, root->child_count());
688 FrameTreeNode* foo_child = root->child_at(0);
689 SiteInstance* foo_site_instance =
690 foo_child->current_frame_host()->GetSiteInstance();
691 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), foo_site_instance);
692 FrameTreeNode* bar_child = root->child_at(1);
693 SiteInstance* bar_site_instance =
694 bar_child->current_frame_host()->GetSiteInstance();
695 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), bar_site_instance);
697 EXPECT_EQ(
698 " Site A ------------ proxies for B C\n"
699 " |--Site B ------- proxies for A C\n"
700 " +--Site C ------- proxies for A B\n"
701 "Where A = http://a.com/\n"
702 " B = http://foo.com/\n"
703 " C = http://bar.com/",
704 DepictFrameTree(root));
706 // Simulate an attempt to detach the root frame from foo_site_instance. This
707 // should kill foo_site_instance's process.
708 RenderFrameProxyHost* foo_mainframe_rfph =
709 root->render_manager()->GetRenderFrameProxyHost(foo_site_instance);
710 content::RenderProcessHostWatcher foo_terminated(
711 foo_mainframe_rfph->GetProcess(),
712 content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
713 FrameHostMsg_Detach evil_msg2(foo_mainframe_rfph->GetRoutingID());
714 IPC::IpcSecurityTestUtil::PwnMessageReceived(
715 foo_mainframe_rfph->GetProcess()->GetChannel(), evil_msg2);
716 foo_terminated.Wait();
718 EXPECT_EQ(
719 " Site A ------------ proxies for B C\n"
720 " |--Site B ------- proxies for A C\n"
721 " +--Site C ------- proxies for A B\n"
722 "Where A = http://a.com/\n"
723 " B = http://foo.com/ (no process)\n"
724 " C = http://bar.com/",
725 DepictFrameTree(root));
728 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NavigateRemoteFrame) {
729 GURL main_url(embedded_test_server()->GetURL(
730 "a.com", "/cross_site_iframe_factory.html?a(a,a(a,a(a)))"));
731 NavigateToURL(shell(), main_url);
733 // It is safe to obtain the root frame tree node here, as it doesn't change.
734 FrameTreeNode* root =
735 static_cast<WebContentsImpl*>(shell()->web_contents())->
736 GetFrameTree()->root();
738 TestNavigationObserver observer(shell()->web_contents());
740 // Load same-site page into iframe.
741 FrameTreeNode* child = root->child_at(0);
742 GURL http_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
743 NavigateFrameToURL(child, http_url);
744 EXPECT_EQ(http_url, observer.last_navigation_url());
745 EXPECT_TRUE(observer.last_navigation_succeeded());
747 // Load cross-site page into iframe.
748 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
749 NavigateFrameToURL(root->child_at(0), url);
750 EXPECT_TRUE(observer.last_navigation_succeeded());
751 EXPECT_EQ(url, observer.last_navigation_url());
753 // Ensure that we have created a new process for the subframe.
754 EXPECT_EQ(
755 " Site A ------------ proxies for B\n"
756 " |--Site B ------- proxies for A\n"
757 " +--Site A ------- proxies for B\n"
758 " |--Site A -- proxies for B\n"
759 " +--Site A -- proxies for B\n"
760 " +--Site A -- proxies for B\n"
761 "Where A = http://a.com/\n"
762 " B = http://foo.com/",
763 DepictFrameTree(root));
764 SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
765 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
767 // Emulate the main frame changing the src of the iframe such that it
768 // navigates cross-site.
769 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
770 NavigateIframeToURL(shell()->web_contents(), "child-0", url);
771 EXPECT_TRUE(observer.last_navigation_succeeded());
772 EXPECT_EQ(url, observer.last_navigation_url());
774 // Check again that a new process is created and is different from the
775 // top level one and the previous one.
776 EXPECT_EQ(
777 " Site A ------------ proxies for C\n"
778 " |--Site C ------- proxies for A\n"
779 " +--Site A ------- proxies for C\n"
780 " |--Site A -- proxies for C\n"
781 " +--Site A -- proxies for C\n"
782 " +--Site A -- proxies for C\n"
783 "Where A = http://a.com/\n"
784 " C = http://bar.com/",
785 DepictFrameTree(root));
787 // Navigate back to the parent's origin and ensure we return to the
788 // parent's process.
789 NavigateFrameToURL(child, http_url);
790 EXPECT_EQ(http_url, observer.last_navigation_url());
791 EXPECT_TRUE(observer.last_navigation_succeeded());
792 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
793 child->current_frame_host()->GetSiteInstance());
796 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
797 NavigateRemoteFrameToBlankAndDataURLs) {
798 GURL main_url(embedded_test_server()->GetURL(
799 "a.com", "/cross_site_iframe_factory.html?a(a,a(a))"));
800 NavigateToURL(shell(), main_url);
802 // It is safe to obtain the root frame tree node here, as it doesn't change.
803 FrameTreeNode* root =
804 static_cast<WebContentsImpl*>(shell()->web_contents())->
805 GetFrameTree()->root();
807 TestNavigationObserver observer(shell()->web_contents());
809 // Load same-site page into iframe.
810 FrameTreeNode* child = root->child_at(0);
811 GURL http_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
812 NavigateFrameToURL(child, http_url);
813 EXPECT_EQ(http_url, observer.last_navigation_url());
814 EXPECT_TRUE(observer.last_navigation_succeeded());
815 EXPECT_EQ(
816 " Site A\n"
817 " |--Site A\n"
818 " +--Site A\n"
819 " +--Site A\n"
820 "Where A = http://a.com/",
821 DepictFrameTree(root));
823 // Load cross-site page into iframe.
824 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
825 NavigateFrameToURL(root->child_at(0), url);
826 EXPECT_TRUE(observer.last_navigation_succeeded());
827 EXPECT_EQ(url, observer.last_navigation_url());
828 EXPECT_EQ(
829 " Site A ------------ proxies for B\n"
830 " |--Site B ------- proxies for A\n"
831 " +--Site A ------- proxies for B\n"
832 " +--Site A -- proxies for B\n"
833 "Where A = http://a.com/\n"
834 " B = http://foo.com/",
835 DepictFrameTree(root));
837 // Navigate iframe to a data URL. The navigation happens from a script in the
838 // parent frame, so the data URL should be committed in the same SiteInstance
839 // as the parent frame.
840 GURL data_url("data:text/html,dataurl");
841 NavigateIframeToURL(shell()->web_contents(), "child-0", data_url);
842 EXPECT_TRUE(observer.last_navigation_succeeded());
843 EXPECT_EQ(data_url, observer.last_navigation_url());
845 // Ensure that we have navigated using the top level process.
846 EXPECT_EQ(
847 " Site A\n"
848 " |--Site A\n"
849 " +--Site A\n"
850 " +--Site A\n"
851 "Where A = http://a.com/",
852 DepictFrameTree(root));
854 // Load cross-site page into iframe.
855 url = embedded_test_server()->GetURL("bar.com", "/title2.html");
856 NavigateFrameToURL(root->child_at(0), url);
857 EXPECT_TRUE(observer.last_navigation_succeeded());
858 EXPECT_EQ(url, observer.last_navigation_url());
859 EXPECT_EQ(
860 " Site A ------------ proxies for C\n"
861 " |--Site C ------- proxies for A\n"
862 " +--Site A ------- proxies for C\n"
863 " +--Site A -- proxies for C\n"
864 "Where A = http://a.com/\n"
865 " C = http://bar.com/",
866 DepictFrameTree(root));
868 // Navigate iframe to about:blank. The navigation happens from a script in the
869 // parent frame, so it should be committed in the same SiteInstance as the
870 // parent frame.
871 GURL about_blank_url("about:blank");
872 NavigateIframeToURL(shell()->web_contents(), "child-0", about_blank_url);
873 EXPECT_TRUE(observer.last_navigation_succeeded());
874 EXPECT_EQ(about_blank_url, observer.last_navigation_url());
876 // Ensure that we have navigated using the top level process.
877 EXPECT_EQ(
878 " Site A\n"
879 " |--Site A\n"
880 " +--Site A\n"
881 " +--Site A\n"
882 "Where A = http://a.com/",
883 DepictFrameTree(root));
886 // This test checks that killing a renderer process of a remote frame
887 // and then navigating some other frame to the same SiteInstance of the killed
888 // process works properly.
889 // This can be illustrated as follows,
890 // where 1/2/3 are FrameTreeNode-s and A/B are processes and B* is the killed
891 // B process:
893 // 1 A A A
894 // / \ -> / \ -> Kill B -> / \ -> Navigate 3 to B -> / \ .
895 // 2 3 B A B* A B* B
897 // Initially, node1.proxy_hosts_ = {B}
898 // After we kill B, we make sure B stays in node1.proxy_hosts_, then we navigate
899 // 3 to B and we expect that to complete normally.
900 // See http://crbug.com/432107.
902 // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
903 // site B and stays in not rendered state.
904 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
905 NavigateRemoteFrameToKilledProcess) {
906 GURL main_url(embedded_test_server()->GetURL(
907 "foo.com", "/cross_site_iframe_factory.html?foo.com(bar.com, foo.com)"));
908 NavigateToURL(shell(), main_url);
910 // It is safe to obtain the root frame tree node here, as it doesn't change.
911 FrameTreeNode* root =
912 static_cast<WebContentsImpl*>(shell()->web_contents())->
913 GetFrameTree()->root();
915 TestNavigationObserver observer(shell()->web_contents());
916 ASSERT_EQ(2U, root->child_count());
918 // Make sure node2 points to the correct cross-site page.
919 GURL site_b_url = embedded_test_server()->GetURL(
920 "bar.com", "/cross_site_iframe_factory.html?bar.com()");
921 FrameTreeNode* node2 = root->child_at(0);
922 EXPECT_EQ(site_b_url, node2->current_url());
924 // Kill that cross-site renderer.
925 RenderProcessHost* child_process =
926 node2->current_frame_host()->GetProcess();
927 RenderProcessHostWatcher crash_observer(
928 child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
929 child_process->Shutdown(0, false);
930 crash_observer.Wait();
932 // Now navigate the second iframe (node3) to the same site as the node2.
933 FrameTreeNode* node3 = root->child_at(1);
934 NavigateFrameToURL(node3, site_b_url);
935 EXPECT_TRUE(observer.last_navigation_succeeded());
936 EXPECT_EQ(site_b_url, observer.last_navigation_url());
939 // This test is similar to
940 // SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcess with
941 // addition that node2 also has a cross-origin frame to site C.
943 // 1 A A A
944 // / \ / \ / \ / \ .
945 // 2 3 -> B A -> Kill B -> B* A -> Navigate 3 -> B* B
946 // / /
947 // 4 C
949 // Initially, node1.proxy_hosts_ = {B, C}
950 // After we kill B, we make sure B stays in node1.proxy_hosts_, but
951 // C gets cleared from node1.proxy_hosts_.
953 // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
954 // site B and stays in not rendered state.
955 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
956 NavigateRemoteFrameToKilledProcessWithSubtree) {
957 GURL main_url(embedded_test_server()->GetURL(
958 "a.com", "/cross_site_iframe_factory.html?a(bar(baz), a)"));
959 NavigateToURL(shell(), main_url);
961 // It is safe to obtain the root frame tree node here, as it doesn't change.
962 FrameTreeNode* root =
963 static_cast<WebContentsImpl*>(shell()->web_contents())->
964 GetFrameTree()->root();
965 TestNavigationObserver observer(shell()->web_contents());
967 ASSERT_EQ(2U, root->child_count());
969 GURL site_b_url(embedded_test_server()->GetURL(
970 "bar.com", "/cross_site_iframe_factory.html?bar(baz())"));
971 // We can't use a TestNavigationObserver to verify the URL here,
972 // since the frame has children that may have clobbered it in the observer.
973 EXPECT_EQ(site_b_url, root->child_at(0)->current_url());
975 // Ensure that a new process is created for node2.
976 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
977 root->child_at(0)->current_frame_host()->GetSiteInstance());
978 // Ensure that a new process is *not* created for node3.
979 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
980 root->child_at(1)->current_frame_host()->GetSiteInstance());
982 ASSERT_EQ(1U, root->child_at(0)->child_count());
984 // Make sure node4 points to the correct cross-site page.
985 FrameTreeNode* node4 = root->child_at(0)->child_at(0);
986 GURL site_c_url(embedded_test_server()->GetURL(
987 "baz.com", "/cross_site_iframe_factory.html?baz()"));
988 EXPECT_EQ(site_c_url, node4->current_url());
990 // |site_instance_c| is expected to go away once we kill |child_process_b|
991 // below, so create a local scope so we can extend the lifetime of
992 // |site_instance_c| with a refptr.
994 // Initially each frame has proxies for the other sites.
995 EXPECT_EQ(
996 " Site A ------------ proxies for B C\n"
997 " |--Site B ------- proxies for A C\n"
998 " | +--Site C -- proxies for A B\n"
999 " +--Site A ------- proxies for B C\n"
1000 "Where A = http://a.com/\n"
1001 " B = http://bar.com/\n"
1002 " C = http://baz.com/",
1003 DepictFrameTree(root));
1005 // Kill the render process for Site B.
1006 RenderProcessHost* child_process_b =
1007 root->child_at(0)->current_frame_host()->GetProcess();
1008 RenderProcessHostWatcher crash_observer(
1009 child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1010 child_process_b->Shutdown(0, false);
1011 crash_observer.Wait();
1013 // The Site C frame (a child of the crashed Site B frame) should go away,
1014 // and there should be no remaining proxies for site C anywhere.
1015 EXPECT_EQ(
1016 " Site A ------------ proxies for B\n"
1017 " |--Site B ------- proxies for A\n"
1018 " +--Site A ------- proxies for B\n"
1019 "Where A = http://a.com/\n"
1020 " B = http://bar.com/ (no process)",
1021 DepictFrameTree(root));
1024 // Now navigate the second iframe (node3) to Site B also.
1025 FrameTreeNode* node3 = root->child_at(1);
1026 GURL url = embedded_test_server()->GetURL("bar.com", "/title1.html");
1027 NavigateFrameToURL(node3, url);
1028 EXPECT_TRUE(observer.last_navigation_succeeded());
1029 EXPECT_EQ(url, observer.last_navigation_url());
1031 EXPECT_EQ(
1032 " Site A ------------ proxies for B\n"
1033 " |--Site B ------- proxies for A\n"
1034 " +--Site B ------- proxies for A\n"
1035 "Where A = http://a.com/\n"
1036 " B = http://bar.com/",
1037 DepictFrameTree(root));
1040 // Verify that killing a cross-site frame's process B and then navigating a
1041 // frame to B correctly recreates all proxies in B.
1043 // 1 A A A
1044 // / | \ / | \ / | \ / | \ .
1045 // 2 3 4 -> B A A -> Kill B -> B* A A -> B* B A
1047 // After the last step, the test sends a postMessage from node 3 to node 4,
1048 // verifying that a proxy for node 4 has been recreated in process B. This
1049 // verifies the fix for https://crbug.com/478892.
1050 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1051 NavigatingToKilledProcessRestoresAllProxies) {
1052 // Navigate to a page with three frames: one cross-site and two same-site.
1053 GURL main_url(embedded_test_server()->GetURL(
1054 "a.com", "/frame_tree/page_with_three_frames.html"));
1055 NavigateToURL(shell(), main_url);
1057 // It is safe to obtain the root frame tree node here, as it doesn't change.
1058 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1059 ->GetFrameTree()
1060 ->root();
1061 TestNavigationObserver observer(shell()->web_contents());
1063 EXPECT_EQ(
1064 " Site A ------------ proxies for B\n"
1065 " |--Site B ------- proxies for A\n"
1066 " |--Site A ------- proxies for B\n"
1067 " +--Site A ------- proxies for B\n"
1068 "Where A = http://a.com/\n"
1069 " B = http://b.com/",
1070 DepictFrameTree(root));
1072 // Kill the first subframe's b.com renderer.
1073 RenderProcessHost* child_process =
1074 root->child_at(0)->current_frame_host()->GetProcess();
1075 RenderProcessHostWatcher crash_observer(
1076 child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1077 child_process->Shutdown(0, false);
1078 crash_observer.Wait();
1080 // Navigate the second subframe to b.com to recreate the b.com process.
1081 GURL b_url = embedded_test_server()->GetURL("b.com", "/post_message.html");
1082 NavigateFrameToURL(root->child_at(1), b_url);
1083 // TODO(alexmos): This can be removed once TestFrameNavigationObserver is
1084 // fixed to use DidFinishLoad.
1085 EXPECT_TRUE(
1086 WaitForRenderFrameReady(root->child_at(1)->current_frame_host()));
1087 EXPECT_TRUE(observer.last_navigation_succeeded());
1088 EXPECT_EQ(b_url, observer.last_navigation_url());
1089 EXPECT_TRUE(root->child_at(1)->current_frame_host()->IsRenderFrameLive());
1091 EXPECT_EQ(
1092 " Site A ------------ proxies for B\n"
1093 " |--Site B ------- proxies for A\n"
1094 " |--Site B ------- proxies for A\n"
1095 " +--Site A ------- proxies for B\n"
1096 "Where A = http://a.com/\n"
1097 " B = http://b.com/",
1098 DepictFrameTree(root));
1100 // Check that third subframe's proxy is available in the b.com process by
1101 // sending it a postMessage from second subframe, and waiting for a reply.
1102 PostMessageAndWaitForReply(root->child_at(1),
1103 "postToSibling('subframe-msg','frame3')",
1104 "\"done-frame2\"");
1107 // Verify that proxy creation doesn't recreate a crashed process if no frame
1108 // will be created in it.
1110 // 1 A A A
1111 // / | \ / | \ / | \ / | \ .
1112 // 2 3 4 -> B A A -> Kill B -> B* A A -> B* A A
1113 // \ .
1114 // A
1116 // The test kills process B (node 2), creates a child frame of node 4 in
1117 // process A, and then checks that process B isn't resurrected to create a
1118 // proxy for the new child frame. See https://crbug.com/476846.
1119 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1120 CreateChildFrameAfterKillingProcess) {
1121 // Navigate to a page with three frames: one cross-site and two same-site.
1122 GURL main_url(embedded_test_server()->GetURL(
1123 "a.com", "/frame_tree/page_with_three_frames.html"));
1124 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1126 // It is safe to obtain the root frame tree node here, as it doesn't change.
1127 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1128 ->GetFrameTree()
1129 ->root();
1131 EXPECT_EQ(
1132 " Site A ------------ proxies for B\n"
1133 " |--Site B ------- proxies for A\n"
1134 " |--Site A ------- proxies for B\n"
1135 " +--Site A ------- proxies for B\n"
1136 "Where A = http://a.com/\n"
1137 " B = http://b.com/",
1138 DepictFrameTree(root));
1139 SiteInstance* b_site_instance =
1140 root->child_at(0)->current_frame_host()->GetSiteInstance();
1142 // Kill the first subframe's renderer (B).
1143 RenderProcessHost* child_process =
1144 root->child_at(0)->current_frame_host()->GetProcess();
1145 RenderProcessHostWatcher crash_observer(
1146 child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1147 child_process->Shutdown(0, false);
1148 crash_observer.Wait();
1150 // Add a new child frame to the third subframe.
1151 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 1);
1152 EXPECT_TRUE(ExecuteScript(
1153 root->child_at(2)->current_frame_host(),
1154 "document.body.appendChild(document.createElement('iframe'));"));
1155 frame_observer.Wait();
1157 // The new frame should have a RenderFrameProxyHost for B, but it should not
1158 // be alive, and B should still not have a process (verified by last line of
1159 // expected DepictFrameTree output).
1160 EXPECT_EQ(
1161 " Site A ------------ proxies for B\n"
1162 " |--Site B ------- proxies for A\n"
1163 " |--Site A ------- proxies for B\n"
1164 " +--Site A ------- proxies for B\n"
1165 " +--Site A -- proxies for B\n"
1166 "Where A = http://a.com/\n"
1167 " B = http://b.com/ (no process)",
1168 DepictFrameTree(root));
1169 FrameTreeNode* grandchild = root->child_at(2)->child_at(0);
1170 RenderFrameProxyHost* grandchild_rfph =
1171 grandchild->render_manager()->GetRenderFrameProxyHost(b_site_instance);
1172 EXPECT_FALSE(grandchild_rfph->is_render_frame_proxy_live());
1174 // Navigate the second subframe to b.com to recreate process B.
1175 TestNavigationObserver observer(shell()->web_contents());
1176 GURL b_url = embedded_test_server()->GetURL("b.com", "/title1.html");
1177 NavigateFrameToURL(root->child_at(1), b_url);
1178 EXPECT_TRUE(observer.last_navigation_succeeded());
1179 EXPECT_EQ(b_url, observer.last_navigation_url());
1181 // Ensure that the grandchild RenderFrameProxy in B was created when process
1182 // B was restored.
1183 EXPECT_TRUE(grandchild_rfph->is_render_frame_proxy_live());
1186 // Verify that creating a child frame after killing and reloading an opener
1187 // process doesn't crash. See https://crbug.com/501152.
1188 // 1. Navigate to site A.
1189 // 2. Open a popup with window.open and navigate it cross-process to site B.
1190 // 3. Kill process A for the original tab.
1191 // 4. Reload the original tab to resurrect process A.
1192 // 5. Add a child frame to the top-level frame in the popup tab B.
1193 // In step 5, we try to create proxies for the child frame in all SiteInstances
1194 // for which its parent has proxies. This includes A. However, even though
1195 // process A is live (step 4), the parent proxy in A is not live (which was
1196 // incorrectly assumed previously). This is because step 4 does not resurrect
1197 // proxies for popups opened before the crash.
1198 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1199 CreateChildFrameAfterKillingOpener) {
1200 GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
1201 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1203 // It is safe to obtain the root frame tree node here, as it doesn't change.
1204 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1205 ->GetFrameTree()
1206 ->root();
1207 SiteInstance* site_instance_a = root->current_frame_host()->GetSiteInstance();
1209 // Open a popup and navigate it cross-process to b.com.
1210 ShellAddedObserver new_shell_observer;
1211 EXPECT_TRUE(ExecuteScript(root->current_frame_host(),
1212 "popup = window.open('about:blank');"));
1213 Shell* popup = new_shell_observer.GetShell();
1214 GURL popup_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
1215 EXPECT_TRUE(NavigateToURL(popup, popup_url));
1217 // Verify that each top-level frame has proxies in the other's SiteInstance.
1218 FrameTreeNode* popup_root =
1219 static_cast<WebContentsImpl*>(popup->web_contents())
1220 ->GetFrameTree()
1221 ->root();
1222 EXPECT_EQ(
1223 " Site A ------------ proxies for B\n"
1224 "Where A = http://a.com/\n"
1225 " B = http://b.com/",
1226 DepictFrameTree(root));
1227 EXPECT_EQ(
1228 " Site B ------------ proxies for A\n"
1229 "Where A = http://a.com/\n"
1230 " B = http://b.com/",
1231 DepictFrameTree(popup_root));
1233 // Kill the first window's renderer (a.com).
1234 RenderProcessHost* child_process = root->current_frame_host()->GetProcess();
1235 RenderProcessHostWatcher crash_observer(
1236 child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1237 child_process->Shutdown(0, false);
1238 crash_observer.Wait();
1239 EXPECT_FALSE(root->current_frame_host()->IsRenderFrameLive());
1241 // The proxy for the popup in a.com should've died.
1242 RenderFrameProxyHost* rfph =
1243 popup_root->render_manager()->GetRenderFrameProxyHost(site_instance_a);
1244 EXPECT_FALSE(rfph->is_render_frame_proxy_live());
1246 // Recreate the a.com renderer.
1247 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1248 EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
1250 // The popup's proxy in a.com should still not be live. Re-navigating the
1251 // main window to a.com doesn't reinitialize a.com proxies for popups
1252 // previously opened from the main window.
1253 EXPECT_FALSE(rfph->is_render_frame_proxy_live());
1255 // Add a new child frame on the popup.
1256 RenderFrameHostCreatedObserver frame_observer(popup->web_contents(), 1);
1257 EXPECT_TRUE(ExecuteScript(
1258 popup->web_contents(),
1259 "document.body.appendChild(document.createElement('iframe'));"));
1260 frame_observer.Wait();
1262 // Both the child frame's and its parent's proxies should still not be live.
1263 // The main page can't reach them since it lost reference to the popup after
1264 // it crashed, so there is no need to create them.
1265 EXPECT_FALSE(rfph->is_render_frame_proxy_live());
1266 RenderFrameProxyHost* child_rfph =
1267 popup_root->child_at(0)->render_manager()->GetRenderFrameProxyHost(
1268 site_instance_a);
1269 EXPECT_TRUE(child_rfph);
1270 EXPECT_FALSE(child_rfph->is_render_frame_proxy_live());
1273 // In A-embed-B-embed-C scenario, verify that killing process B clears proxies
1274 // of C from the tree.
1276 // 1 A A
1277 // / \ / \ / \ .
1278 // 2 3 -> B A -> Kill B -> B* A
1279 // / /
1280 // 4 C
1282 // node1 is the root.
1283 // Initially, both node1.proxy_hosts_ and node3.proxy_hosts_ contain C.
1284 // After we kill B, make sure proxies for C are cleared.
1285 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1286 KillingRendererClearsDescendantProxies) {
1287 GURL main_url(embedded_test_server()->GetURL(
1288 "a.com", "/frame_tree/page_with_two_frames_nested.html"));
1289 NavigateToURL(shell(), main_url);
1291 // It is safe to obtain the root frame tree node here, as it doesn't change.
1292 FrameTreeNode* root =
1293 static_cast<WebContentsImpl*>(shell()->web_contents())->
1294 GetFrameTree()->root();
1295 ASSERT_EQ(2U, root->child_count());
1297 GURL site_b_url(
1298 embedded_test_server()->GetURL(
1299 "bar.com", "/frame_tree/page_with_one_frame.html"));
1300 // We can't use a TestNavigationObserver to verify the URL here,
1301 // since the frame has children that may have clobbered it in the observer.
1302 EXPECT_EQ(site_b_url, root->child_at(0)->current_url());
1304 // Ensure that a new process is created for node2.
1305 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1306 root->child_at(0)->current_frame_host()->GetSiteInstance());
1307 // Ensure that a new process is *not* created for node3.
1308 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
1309 root->child_at(1)->current_frame_host()->GetSiteInstance());
1311 ASSERT_EQ(1U, root->child_at(0)->child_count());
1313 // Make sure node4 points to the correct cross-site-page.
1314 FrameTreeNode* node4 = root->child_at(0)->child_at(0);
1315 GURL site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
1316 EXPECT_EQ(site_c_url, node4->current_url());
1318 // |site_instance_c|'s frames and proxies are expected to go away once we kill
1319 // |child_process_b| below.
1320 scoped_refptr<SiteInstanceImpl> site_instance_c =
1321 node4->current_frame_host()->GetSiteInstance();
1323 // Initially proxies for both B and C will be present in the root.
1324 EXPECT_EQ(
1325 " Site A ------------ proxies for B C\n"
1326 " |--Site B ------- proxies for A C\n"
1327 " | +--Site C -- proxies for A B\n"
1328 " +--Site A ------- proxies for B C\n"
1329 "Where A = http://a.com/\n"
1330 " B = http://bar.com/\n"
1331 " C = http://baz.com/",
1332 DepictFrameTree(root));
1334 EXPECT_GT(site_instance_c->active_frame_count(), 0U);
1336 // Kill process B.
1337 RenderProcessHost* child_process_b =
1338 root->child_at(0)->current_frame_host()->GetProcess();
1339 RenderProcessHostWatcher crash_observer(
1340 child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1341 child_process_b->Shutdown(0, false);
1342 crash_observer.Wait();
1344 // Make sure proxy C has gone from root.
1345 // Make sure proxy C has gone from node3 as well.
1346 // Make sure proxy B stays around in root and node3.
1347 EXPECT_EQ(
1348 " Site A ------------ proxies for B\n"
1349 " |--Site B ------- proxies for A\n"
1350 " +--Site A ------- proxies for B\n"
1351 "Where A = http://a.com/\n"
1352 " B = http://bar.com/ (no process)",
1353 DepictFrameTree(root));
1355 EXPECT_EQ(0U, site_instance_c->active_frame_count());
1358 // Crash a subframe and ensures its children are cleared from the FrameTree.
1359 // See http://crbug.com/338508.
1360 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrashSubframe) {
1361 GURL main_url(embedded_test_server()->GetURL(
1362 "a.com", "/cross_site_iframe_factory.html?a(b)"));
1363 NavigateToURL(shell(), main_url);
1365 // Check the subframe process.
1366 FrameTreeNode* root =
1367 static_cast<WebContentsImpl*>(shell()->web_contents())->
1368 GetFrameTree()->root();
1369 EXPECT_EQ(
1370 " Site A ------------ proxies for B\n"
1371 " +--Site B ------- proxies for A\n"
1372 "Where A = http://a.com/\n"
1373 " B = http://b.com/",
1374 DepictFrameTree(root));
1375 FrameTreeNode* child = root->child_at(0);
1376 EXPECT_TRUE(
1377 child->current_frame_host()->render_view_host()->IsRenderViewLive());
1378 EXPECT_TRUE(child->current_frame_host()->IsRenderFrameLive());
1380 // Crash the subframe process.
1381 RenderProcessHost* root_process = root->current_frame_host()->GetProcess();
1382 RenderProcessHost* child_process = child->current_frame_host()->GetProcess();
1384 RenderProcessHostWatcher crash_observer(
1385 child_process,
1386 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1387 child_process->Shutdown(0, false);
1388 crash_observer.Wait();
1391 // Ensure that the child frame still exists but has been cleared.
1392 EXPECT_EQ(
1393 " Site A ------------ proxies for B\n"
1394 " +--Site B ------- proxies for A\n"
1395 "Where A = http://a.com/\n"
1396 " B = http://b.com/ (no process)",
1397 DepictFrameTree(root));
1398 EXPECT_EQ(1U, root->child_count());
1399 EXPECT_EQ(main_url, root->current_url());
1400 EXPECT_EQ(GURL(), child->current_url());
1402 EXPECT_FALSE(
1403 child->current_frame_host()->render_view_host()->IsRenderViewLive());
1404 EXPECT_FALSE(child->current_frame_host()->IsRenderFrameLive());
1405 EXPECT_FALSE(child->current_frame_host()->render_frame_created_);
1407 // Now crash the top-level page to clear the child frame.
1409 RenderProcessHostWatcher crash_observer(
1410 root_process,
1411 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1412 root_process->Shutdown(0, false);
1413 crash_observer.Wait();
1415 EXPECT_EQ(0U, root->child_count());
1416 EXPECT_EQ(GURL(), root->current_url());
1419 // When a new subframe is added, related SiteInstances that can reach the
1420 // subframe should create proxies for it (https://crbug.com/423587). This test
1421 // checks that if A embeds B and later adds a new subframe A2, A2 gets a proxy
1422 // in B's process.
1423 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CreateProxiesForNewFrames) {
1424 GURL main_url(embedded_test_server()->GetURL(
1425 "b.com", "/frame_tree/page_with_one_frame.html"));
1426 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1428 // It is safe to obtain the root frame tree node here, as it doesn't change.
1429 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1430 ->GetFrameTree()
1431 ->root();
1432 ASSERT_EQ(1U, root->child_count());
1434 // Make sure the frame starts out at the correct cross-site URL.
1435 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"),
1436 root->child_at(0)->current_url());
1438 EXPECT_EQ(
1439 " Site A ------------ proxies for B\n"
1440 " +--Site B ------- proxies for A\n"
1441 "Where A = http://b.com/\n"
1442 " B = http://baz.com/",
1443 DepictFrameTree(root));
1445 // Add a new child frame to the top-level frame.
1446 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 1);
1447 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1448 "window.domAutomationController.send("
1449 " addFrame('data:text/html,foo'));"));
1450 frame_observer.Wait();
1452 // The new frame should have a proxy in Site B, for use by the old frame.
1453 EXPECT_EQ(
1454 " Site A ------------ proxies for B\n"
1455 " |--Site B ------- proxies for A\n"
1456 " +--Site A ------- proxies for B\n"
1457 "Where A = http://b.com/\n"
1458 " B = http://baz.com/",
1459 DepictFrameTree(root));
1462 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
1463 // security checks are back in place.
1464 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
1465 // on Android (http://crbug.com/187570).
1466 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1467 DISABLED_CrossSiteIframeRedirectOnce) {
1468 ASSERT_TRUE(test_server()->Start());
1469 net::SpawnedTestServer https_server(
1470 net::SpawnedTestServer::TYPE_HTTPS,
1471 net::SpawnedTestServer::kLocalhost,
1472 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
1473 ASSERT_TRUE(https_server.Start());
1475 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
1476 GURL http_url(test_server()->GetURL("files/title1.html"));
1477 GURL https_url(https_server.GetURL("files/title1.html"));
1479 NavigateToURL(shell(), main_url);
1481 TestNavigationObserver observer(shell()->web_contents());
1483 // Load cross-site client-redirect page into Iframe.
1484 // Should be blocked.
1485 GURL client_redirect_https_url(https_server.GetURL(
1486 "client-redirect?files/title1.html"));
1487 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1488 client_redirect_https_url));
1489 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
1490 EXPECT_EQ(observer.last_navigation_url(), client_redirect_https_url);
1491 EXPECT_FALSE(observer.last_navigation_succeeded());
1495 // Load cross-site server-redirect page into Iframe,
1496 // which redirects to same-site page.
1497 GURL server_redirect_http_url(https_server.GetURL(
1498 "server-redirect?" + http_url.spec()));
1499 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1500 server_redirect_http_url));
1501 EXPECT_EQ(observer.last_navigation_url(), http_url);
1502 EXPECT_TRUE(observer.last_navigation_succeeded());
1506 // Load cross-site server-redirect page into Iframe,
1507 // which redirects to cross-site page.
1508 GURL server_redirect_http_url(https_server.GetURL(
1509 "server-redirect?files/title1.html"));
1510 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1511 server_redirect_http_url));
1512 // DidFailProvisionalLoad when navigating to https_url.
1513 EXPECT_EQ(observer.last_navigation_url(), https_url);
1514 EXPECT_FALSE(observer.last_navigation_succeeded());
1518 // Load same-site server-redirect page into Iframe,
1519 // which redirects to cross-site page.
1520 GURL server_redirect_http_url(test_server()->GetURL(
1521 "server-redirect?" + https_url.spec()));
1522 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1523 server_redirect_http_url));
1525 EXPECT_EQ(observer.last_navigation_url(), https_url);
1526 EXPECT_FALSE(observer.last_navigation_succeeded());
1530 // Load same-site client-redirect page into Iframe,
1531 // which redirects to cross-site page.
1532 GURL client_redirect_http_url(test_server()->GetURL(
1533 "client-redirect?" + https_url.spec()));
1535 RedirectNotificationObserver load_observer2(
1536 NOTIFICATION_LOAD_STOP,
1537 Source<NavigationController>(
1538 &shell()->web_contents()->GetController()));
1540 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1541 client_redirect_http_url));
1543 // Same-site Client-Redirect Page should be loaded successfully.
1544 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
1545 EXPECT_TRUE(observer.last_navigation_succeeded());
1547 // Redirecting to Cross-site Page should be blocked.
1548 load_observer2.Wait();
1549 EXPECT_EQ(observer.last_navigation_url(), https_url);
1550 EXPECT_FALSE(observer.last_navigation_succeeded());
1554 // Load same-site server-redirect page into Iframe,
1555 // which redirects to same-site page.
1556 GURL server_redirect_http_url(test_server()->GetURL(
1557 "server-redirect?files/title1.html"));
1558 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1559 server_redirect_http_url));
1560 EXPECT_EQ(observer.last_navigation_url(), http_url);
1561 EXPECT_TRUE(observer.last_navigation_succeeded());
1565 // Load same-site client-redirect page into Iframe,
1566 // which redirects to same-site page.
1567 GURL client_redirect_http_url(test_server()->GetURL(
1568 "client-redirect?" + http_url.spec()));
1569 RedirectNotificationObserver load_observer2(
1570 NOTIFICATION_LOAD_STOP,
1571 Source<NavigationController>(
1572 &shell()->web_contents()->GetController()));
1574 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1575 client_redirect_http_url));
1577 // Same-site Client-Redirect Page should be loaded successfully.
1578 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
1579 EXPECT_TRUE(observer.last_navigation_succeeded());
1581 // Redirecting to Same-site Page should be loaded successfully.
1582 load_observer2.Wait();
1583 EXPECT_EQ(observer.last_navigation_url(), http_url);
1584 EXPECT_TRUE(observer.last_navigation_succeeded());
1588 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
1589 // security checks are back in place.
1590 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
1591 // on Android (http://crbug.com/187570).
1592 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1593 DISABLED_CrossSiteIframeRedirectTwice) {
1594 ASSERT_TRUE(test_server()->Start());
1595 net::SpawnedTestServer https_server(
1596 net::SpawnedTestServer::TYPE_HTTPS,
1597 net::SpawnedTestServer::kLocalhost,
1598 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
1599 ASSERT_TRUE(https_server.Start());
1601 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
1602 GURL http_url(test_server()->GetURL("files/title1.html"));
1603 GURL https_url(https_server.GetURL("files/title1.html"));
1605 NavigateToURL(shell(), main_url);
1607 TestNavigationObserver observer(shell()->web_contents());
1609 // Load client-redirect page pointing to a cross-site client-redirect page,
1610 // which eventually redirects back to same-site page.
1611 GURL client_redirect_https_url(https_server.GetURL(
1612 "client-redirect?" + http_url.spec()));
1613 GURL client_redirect_http_url(test_server()->GetURL(
1614 "client-redirect?" + client_redirect_https_url.spec()));
1616 // We should wait until second client redirect get cancelled.
1617 RedirectNotificationObserver load_observer2(
1618 NOTIFICATION_LOAD_STOP,
1619 Source<NavigationController>(
1620 &shell()->web_contents()->GetController()));
1622 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1623 client_redirect_http_url));
1625 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
1626 load_observer2.Wait();
1627 EXPECT_EQ(observer.last_navigation_url(), client_redirect_https_url);
1628 EXPECT_FALSE(observer.last_navigation_succeeded());
1632 // Load server-redirect page pointing to a cross-site server-redirect page,
1633 // which eventually redirect back to same-site page.
1634 GURL server_redirect_https_url(https_server.GetURL(
1635 "server-redirect?" + http_url.spec()));
1636 GURL server_redirect_http_url(test_server()->GetURL(
1637 "server-redirect?" + server_redirect_https_url.spec()));
1638 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1639 server_redirect_http_url));
1640 EXPECT_EQ(observer.last_navigation_url(), http_url);
1641 EXPECT_TRUE(observer.last_navigation_succeeded());
1645 // Load server-redirect page pointing to a cross-site server-redirect page,
1646 // which eventually redirects back to cross-site page.
1647 GURL server_redirect_https_url(https_server.GetURL(
1648 "server-redirect?" + https_url.spec()));
1649 GURL server_redirect_http_url(test_server()->GetURL(
1650 "server-redirect?" + server_redirect_https_url.spec()));
1651 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1652 server_redirect_http_url));
1654 // DidFailProvisionalLoad when navigating to https_url.
1655 EXPECT_EQ(observer.last_navigation_url(), https_url);
1656 EXPECT_FALSE(observer.last_navigation_succeeded());
1660 // Load server-redirect page pointing to a cross-site client-redirect page,
1661 // which eventually redirects back to same-site page.
1662 GURL client_redirect_http_url(https_server.GetURL(
1663 "client-redirect?" + http_url.spec()));
1664 GURL server_redirect_http_url(test_server()->GetURL(
1665 "server-redirect?" + client_redirect_http_url.spec()));
1666 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1667 server_redirect_http_url));
1669 // DidFailProvisionalLoad when navigating to client_redirect_http_url.
1670 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
1671 EXPECT_FALSE(observer.last_navigation_succeeded());
1675 // Ensure that when navigating a frame cross-process RenderFrameProxyHosts are
1676 // created in the FrameTree skipping the subtree of the navigating frame.
1677 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1678 ProxyCreationSkipsSubtree) {
1679 GURL main_url(embedded_test_server()->GetURL(
1680 "a.com", "/cross_site_iframe_factory.html?a(a,a(a,a(a)))"));
1681 NavigateToURL(shell(), main_url);
1683 // It is safe to obtain the root frame tree node here, as it doesn't change.
1684 FrameTreeNode* root =
1685 static_cast<WebContentsImpl*>(shell()->web_contents())->
1686 GetFrameTree()->root();
1688 EXPECT_TRUE(root->child_at(1) != NULL);
1689 EXPECT_EQ(2U, root->child_at(1)->child_count());
1692 // Load same-site page into iframe.
1693 TestNavigationObserver observer(shell()->web_contents());
1694 GURL http_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
1695 NavigateFrameToURL(root->child_at(0), http_url);
1696 EXPECT_EQ(http_url, observer.last_navigation_url());
1697 EXPECT_TRUE(observer.last_navigation_succeeded());
1698 EXPECT_EQ(
1699 " Site A\n"
1700 " |--Site A\n"
1701 " +--Site A\n"
1702 " |--Site A\n"
1703 " +--Site A\n"
1704 " +--Site A\n"
1705 "Where A = http://a.com/",
1706 DepictFrameTree(root));
1709 // Create the cross-site URL to navigate to.
1710 GURL cross_site_url =
1711 embedded_test_server()->GetURL("foo.com", "/frame_tree/title2.html");
1713 // Load cross-site page into the second iframe without waiting for the
1714 // navigation to complete. Once LoadURLWithParams returns, we would expect
1715 // proxies to have been created in the frame tree, but children of the
1716 // navigating frame to still be present. The reason is that we don't run the
1717 // message loop, so no IPCs that alter the frame tree can be processed.
1718 FrameTreeNode* child = root->child_at(1);
1719 SiteInstance* site = NULL;
1720 bool browser_side_navigation =
1721 base::CommandLine::ForCurrentProcess()->HasSwitch(
1722 switches::kEnableBrowserSideNavigation);
1723 std::string cross_site_rfh_type =
1724 browser_side_navigation ? "speculative" : "pending";
1726 TestNavigationObserver observer(shell()->web_contents());
1727 TestFrameNavigationObserver navigation_observer(child);
1728 NavigationController::LoadURLParams params(cross_site_url);
1729 params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
1730 params.frame_tree_node_id = child->frame_tree_node_id();
1731 child->navigator()->GetController()->LoadURLWithParams(params);
1733 if (browser_side_navigation) {
1734 site = child->render_manager()
1735 ->speculative_frame_host()
1736 ->GetSiteInstance();
1737 } else {
1738 site = child->render_manager()->pending_frame_host()->GetSiteInstance();
1740 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site);
1742 std::string tree = base::StringPrintf(
1743 " Site A ------------ proxies for B\n"
1744 " |--Site A ------- proxies for B\n"
1745 " +--Site A (B %s)\n"
1746 " |--Site A\n"
1747 " +--Site A\n"
1748 " +--Site A\n"
1749 "Where A = http://a.com/\n"
1750 " B = http://foo.com/",
1751 cross_site_rfh_type.c_str());
1752 EXPECT_EQ(tree, DepictFrameTree(root));
1754 // Now that the verification is done, run the message loop and wait for the
1755 // navigation to complete.
1756 navigation_observer.Wait();
1757 EXPECT_FALSE(child->render_manager()->pending_frame_host());
1758 EXPECT_TRUE(observer.last_navigation_succeeded());
1759 EXPECT_EQ(cross_site_url, observer.last_navigation_url());
1761 EXPECT_EQ(
1762 " Site A ------------ proxies for B\n"
1763 " |--Site A ------- proxies for B\n"
1764 " +--Site B ------- proxies for A\n"
1765 "Where A = http://a.com/\n"
1766 " B = http://foo.com/",
1767 DepictFrameTree(root));
1770 // Load another cross-site page into the same iframe.
1771 cross_site_url = embedded_test_server()->GetURL("bar.com", "/title3.html");
1773 // Perform the same checks as the first cross-site navigation, since
1774 // there have been issues in subsequent cross-site navigations. Also ensure
1775 // that the SiteInstance has properly changed.
1776 // TODO(nasko): Once we have proper cleanup of resources, add code to
1777 // verify that the intermediate SiteInstance/RenderFrameHost have been
1778 // properly cleaned up.
1779 TestNavigationObserver observer(shell()->web_contents());
1780 TestFrameNavigationObserver navigation_observer(child);
1781 NavigationController::LoadURLParams params(cross_site_url);
1782 params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
1783 params.frame_tree_node_id = child->frame_tree_node_id();
1784 child->navigator()->GetController()->LoadURLWithParams(params);
1786 SiteInstance* site2;
1787 if (browser_side_navigation) {
1788 site2 = child->render_manager()
1789 ->speculative_frame_host()
1790 ->GetSiteInstance();
1791 } else {
1792 site2 = child->render_manager()->pending_frame_host()->GetSiteInstance();
1794 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site2);
1795 EXPECT_NE(site, site2);
1797 std::string tree = base::StringPrintf(
1798 " Site A ------------ proxies for B C\n"
1799 " |--Site A ------- proxies for B C\n"
1800 " +--Site B (C %s) -- proxies for A\n"
1801 "Where A = http://a.com/\n"
1802 " B = http://foo.com/\n"
1803 " C = http://bar.com/",
1804 cross_site_rfh_type.c_str());
1805 EXPECT_EQ(tree, DepictFrameTree(root));
1807 navigation_observer.Wait();
1808 EXPECT_TRUE(observer.last_navigation_succeeded());
1809 EXPECT_EQ(cross_site_url, observer.last_navigation_url());
1810 EXPECT_EQ(0U, child->child_count());
1814 // Verify origin replication with an A-embed-B-embed-C-embed-A hierarchy.
1815 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OriginReplication) {
1816 GURL main_url(embedded_test_server()->GetURL(
1817 "a.com", "/cross_site_iframe_factory.html?a(b(c(a),b), a)"));
1818 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1820 // It is safe to obtain the root frame tree node here, as it doesn't change.
1821 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1822 ->GetFrameTree()
1823 ->root();
1825 EXPECT_EQ(
1826 " Site A ------------ proxies for B C\n"
1827 " |--Site B ------- proxies for A C\n" // tiptop_child
1828 " | |--Site C -- proxies for A B\n" // middle_child
1829 " | | +--Site A -- proxies for B C\n" // lowest_child
1830 " | +--Site B -- proxies for A C\n"
1831 " +--Site A ------- proxies for B C\n"
1832 "Where A = http://a.com/\n"
1833 " B = http://b.com/\n"
1834 " C = http://c.com/",
1835 DepictFrameTree(root));
1837 std::string a_origin = embedded_test_server()->GetURL("a.com", "/").spec();
1838 std::string b_origin = embedded_test_server()->GetURL("b.com", "/").spec();
1839 std::string c_origin = embedded_test_server()->GetURL("c.com", "/").spec();
1840 FrameTreeNode* tiptop_child = root->child_at(0);
1841 FrameTreeNode* middle_child = root->child_at(0)->child_at(0);
1842 FrameTreeNode* lowest_child = root->child_at(0)->child_at(0)->child_at(0);
1844 // Check that b.com frame's location.ancestorOrigins contains the correct
1845 // origin for the parent. The origin should have been replicated as part of
1846 // the ViewMsg_New message that created the parent's RenderFrameProxy in
1847 // b.com's process.
1848 int ancestor_origins_length = 0;
1849 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1850 tiptop_child->current_frame_host(),
1851 "window.domAutomationController.send(location.ancestorOrigins.length);",
1852 &ancestor_origins_length));
1853 EXPECT_EQ(1, ancestor_origins_length);
1854 std::string result;
1855 EXPECT_TRUE(ExecuteScriptAndExtractString(
1856 tiptop_child->current_frame_host(),
1857 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1858 &result));
1859 EXPECT_EQ(a_origin, result + "/");
1861 // Check that c.com frame's location.ancestorOrigins contains the correct
1862 // origin for its two ancestors. The topmost parent origin should be
1863 // replicated as part of ViewMsg_New, and the middle frame (b.com's) origin
1864 // should be replicated as part of FrameMsg_NewFrameProxy sent for b.com's
1865 // frame in c.com's process.
1866 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1867 middle_child->current_frame_host(),
1868 "window.domAutomationController.send(location.ancestorOrigins.length);",
1869 &ancestor_origins_length));
1870 EXPECT_EQ(2, ancestor_origins_length);
1871 EXPECT_TRUE(ExecuteScriptAndExtractString(
1872 middle_child->current_frame_host(),
1873 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1874 &result));
1875 EXPECT_EQ(b_origin, result + "/");
1876 EXPECT_TRUE(ExecuteScriptAndExtractString(
1877 middle_child->current_frame_host(),
1878 "window.domAutomationController.send(location.ancestorOrigins[1]);",
1879 &result));
1880 EXPECT_EQ(a_origin, result + "/");
1882 // Check that the nested a.com frame's location.ancestorOrigins contains the
1883 // correct origin for its three ancestors.
1884 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1885 lowest_child->current_frame_host(),
1886 "window.domAutomationController.send(location.ancestorOrigins.length);",
1887 &ancestor_origins_length));
1888 EXPECT_EQ(3, ancestor_origins_length);
1889 EXPECT_TRUE(ExecuteScriptAndExtractString(
1890 lowest_child->current_frame_host(),
1891 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1892 &result));
1893 EXPECT_EQ(c_origin, result + "/");
1894 EXPECT_TRUE(ExecuteScriptAndExtractString(
1895 lowest_child->current_frame_host(),
1896 "window.domAutomationController.send(location.ancestorOrigins[1]);",
1897 &result));
1898 EXPECT_EQ(b_origin, result + "/");
1899 EXPECT_TRUE(ExecuteScriptAndExtractString(
1900 lowest_child->current_frame_host(),
1901 "window.domAutomationController.send(location.ancestorOrigins[2]);",
1902 &result));
1903 EXPECT_EQ(a_origin, result + "/");
1906 // Check that iframe sandbox flags are replicated correctly.
1907 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SandboxFlagsReplication) {
1908 GURL main_url(embedded_test_server()->GetURL("/sandboxed_frames.html"));
1909 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1911 // It is safe to obtain the root frame tree node here, as it doesn't change.
1912 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1913 ->GetFrameTree()
1914 ->root();
1916 TestNavigationObserver observer(shell()->web_contents());
1918 // Navigate the second (sandboxed) subframe to a cross-site page with a
1919 // subframe.
1920 GURL foo_url(
1921 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
1922 NavigateFrameToURL(root->child_at(1), foo_url);
1923 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1925 // We can't use a TestNavigationObserver to verify the URL here,
1926 // since the frame has children that may have clobbered it in the observer.
1927 EXPECT_EQ(foo_url, root->child_at(1)->current_url());
1929 // Load cross-site page into subframe's subframe.
1930 ASSERT_EQ(2U, root->child_at(1)->child_count());
1931 GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
1932 NavigateFrameToURL(root->child_at(1)->child_at(0), bar_url);
1933 EXPECT_TRUE(observer.last_navigation_succeeded());
1934 EXPECT_EQ(bar_url, observer.last_navigation_url());
1936 // Opening a popup in the sandboxed foo.com iframe should fail.
1937 bool success = false;
1938 EXPECT_TRUE(
1939 ExecuteScriptAndExtractBool(root->child_at(1)->current_frame_host(),
1940 "window.domAutomationController.send("
1941 "!window.open('data:text/html,dataurl'));",
1942 &success));
1943 EXPECT_TRUE(success);
1944 EXPECT_EQ(1u, Shell::windows().size());
1946 // Opening a popup in a frame whose parent is sandboxed should also fail.
1947 // Here, bar.com frame's sandboxed parent frame is a remote frame in
1948 // bar.com's process.
1949 success = false;
1950 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1951 root->child_at(1)->child_at(0)->current_frame_host(),
1952 "window.domAutomationController.send("
1953 "!window.open('data:text/html,dataurl'));",
1954 &success));
1955 EXPECT_TRUE(success);
1956 EXPECT_EQ(1u, Shell::windows().size());
1958 // Same, but now try the case where bar.com frame's sandboxed parent is a
1959 // local frame in bar.com's process.
1960 success = false;
1961 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1962 root->child_at(2)->child_at(0)->current_frame_host(),
1963 "window.domAutomationController.send("
1964 "!window.open('data:text/html,dataurl'));",
1965 &success));
1966 EXPECT_TRUE(success);
1967 EXPECT_EQ(1u, Shell::windows().size());
1969 // Check that foo.com frame's location.ancestorOrigins contains the correct
1970 // origin for the parent, which should be unaffected by sandboxing.
1971 int ancestor_origins_length = 0;
1972 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1973 root->child_at(1)->current_frame_host(),
1974 "window.domAutomationController.send(location.ancestorOrigins.length);",
1975 &ancestor_origins_length));
1976 EXPECT_EQ(1, ancestor_origins_length);
1977 std::string result;
1978 EXPECT_TRUE(ExecuteScriptAndExtractString(
1979 root->child_at(1)->current_frame_host(),
1980 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1981 &result));
1982 EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
1984 // Now check location.ancestorOrigins for the bar.com frame. The middle frame
1985 // (foo.com's) origin should be unique, since that frame is sandboxed, and
1986 // the top frame should match |main_url|.
1987 FrameTreeNode* bottom_child = root->child_at(1)->child_at(0);
1988 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1989 bottom_child->current_frame_host(),
1990 "window.domAutomationController.send(location.ancestorOrigins.length);",
1991 &ancestor_origins_length));
1992 EXPECT_EQ(2, ancestor_origins_length);
1993 EXPECT_TRUE(ExecuteScriptAndExtractString(
1994 bottom_child->current_frame_host(),
1995 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1996 &result));
1997 EXPECT_EQ("null", result);
1998 EXPECT_TRUE(ExecuteScriptAndExtractString(
1999 bottom_child->current_frame_host(),
2000 "window.domAutomationController.send(location.ancestorOrigins[1]);",
2001 &result));
2002 EXPECT_EQ(main_url.GetOrigin().spec(), result + "/");
2005 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
2006 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicSandboxFlags) {
2007 GURL main_url(
2008 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
2009 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2011 // It is safe to obtain the root frame tree node here, as it doesn't change.
2012 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2013 ->GetFrameTree()
2014 ->root();
2016 TestNavigationObserver observer(shell()->web_contents());
2017 ASSERT_EQ(2U, root->child_count());
2019 // Make sure first frame starts out at the correct cross-site page.
2020 EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"),
2021 root->child_at(0)->current_url());
2023 // Navigate second frame to another cross-site page.
2024 GURL baz_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
2025 NavigateFrameToURL(root->child_at(1), baz_url);
2026 EXPECT_TRUE(observer.last_navigation_succeeded());
2027 EXPECT_EQ(baz_url, observer.last_navigation_url());
2029 // Both frames should not be sandboxed to start with.
2030 EXPECT_EQ(blink::WebSandboxFlags::None,
2031 root->child_at(0)->current_replication_state().sandbox_flags);
2032 EXPECT_EQ(blink::WebSandboxFlags::None,
2033 root->child_at(0)->effective_sandbox_flags());
2034 EXPECT_EQ(blink::WebSandboxFlags::None,
2035 root->child_at(1)->current_replication_state().sandbox_flags);
2036 EXPECT_EQ(blink::WebSandboxFlags::None,
2037 root->child_at(1)->effective_sandbox_flags());
2039 // Dynamically update sandbox flags for the first frame.
2040 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
2041 "window.domAutomationController.send("
2042 "document.querySelector('iframe').sandbox="
2043 "'allow-scripts');"));
2045 // Check that updated sandbox flags are propagated to browser process.
2046 // The new flags should be set in current_replication_state(), while
2047 // effective_sandbox_flags() should still reflect the old flags, because
2048 // sandbox flag updates take place only after navigations. "allow-scripts"
2049 // resets both SandboxFlags::Scripts and SandboxFlags::AutomaticFeatures bits
2050 // per blink::parseSandboxPolicy().
2051 blink::WebSandboxFlags expected_flags =
2052 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
2053 ~blink::WebSandboxFlags::AutomaticFeatures;
2054 EXPECT_EQ(expected_flags,
2055 root->child_at(0)->current_replication_state().sandbox_flags);
2056 EXPECT_EQ(blink::WebSandboxFlags::None,
2057 root->child_at(0)->effective_sandbox_flags());
2059 // Navigate the first frame to a page on the same site. The new sandbox
2060 // flags should take effect.
2061 GURL bar_url(
2062 embedded_test_server()->GetURL("bar.com", "/frame_tree/2-4.html"));
2063 NavigateFrameToURL(root->child_at(0), bar_url);
2064 // (The new page has a subframe; wait for it to load as well.)
2065 ASSERT_TRUE(WaitForLoadStop(shell()->web_contents()));
2066 EXPECT_EQ(bar_url, root->child_at(0)->current_url());
2067 ASSERT_EQ(1U, root->child_at(0)->child_count());
2069 EXPECT_EQ(
2070 " Site A ------------ proxies for B C\n"
2071 " |--Site B ------- proxies for A C\n"
2072 " | +--Site B -- proxies for A C\n"
2073 " +--Site C ------- proxies for A B\n"
2074 "Where A = http://127.0.0.1/\n"
2075 " B = http://bar.com/\n"
2076 " C = http://baz.com/",
2077 DepictFrameTree(root));
2079 // Confirm that the browser process has updated the frame's current sandbox
2080 // flags.
2081 EXPECT_EQ(expected_flags,
2082 root->child_at(0)->current_replication_state().sandbox_flags);
2083 EXPECT_EQ(expected_flags, root->child_at(0)->effective_sandbox_flags());
2085 // Opening a popup in the now-sandboxed frame should fail.
2086 bool success = false;
2087 EXPECT_TRUE(
2088 ExecuteScriptAndExtractBool(root->child_at(0)->current_frame_host(),
2089 "window.domAutomationController.send("
2090 "!window.open('data:text/html,dataurl'));",
2091 &success));
2092 EXPECT_TRUE(success);
2093 EXPECT_EQ(1u, Shell::windows().size());
2095 // Navigate the child of the now-sandboxed frame to a page on baz.com. The
2096 // child should inherit the latest sandbox flags from its parent frame, which
2097 // is currently a proxy in baz.com's renderer process. This checks that the
2098 // proxies of |root->child_at(0)| were also updated with the latest sandbox
2099 // flags.
2100 GURL baz_child_url(embedded_test_server()->GetURL("baz.com", "/title2.html"));
2101 NavigateFrameToURL(root->child_at(0)->child_at(0), baz_child_url);
2102 EXPECT_TRUE(observer.last_navigation_succeeded());
2103 EXPECT_EQ(baz_child_url, observer.last_navigation_url());
2105 EXPECT_EQ(
2106 " Site A ------------ proxies for B C\n"
2107 " |--Site B ------- proxies for A C\n"
2108 " | +--Site C -- proxies for A B\n"
2109 " +--Site C ------- proxies for A B\n"
2110 "Where A = http://127.0.0.1/\n"
2111 " B = http://bar.com/\n"
2112 " C = http://baz.com/",
2113 DepictFrameTree(root));
2115 // Opening a popup in the child of a sandboxed frame should fail.
2116 success = false;
2117 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2118 root->child_at(0)->child_at(0)->current_frame_host(),
2119 "window.domAutomationController.send("
2120 "!window.open('data:text/html,dataurl'));",
2121 &success));
2122 EXPECT_TRUE(success);
2123 EXPECT_EQ(1u, Shell::windows().size());
2126 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
2127 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2128 DynamicSandboxFlagsRemoteToLocal) {
2129 GURL main_url(
2130 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
2131 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2133 // It is safe to obtain the root frame tree node here, as it doesn't change.
2134 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2135 ->GetFrameTree()
2136 ->root();
2138 TestNavigationObserver observer(shell()->web_contents());
2139 ASSERT_EQ(2U, root->child_count());
2141 // Make sure the two frames starts out at correct URLs.
2142 EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"),
2143 root->child_at(0)->current_url());
2144 EXPECT_EQ(embedded_test_server()->GetURL("/title1.html"),
2145 root->child_at(1)->current_url());
2147 // Update the second frame's sandbox flags.
2148 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
2149 "window.domAutomationController.send("
2150 "document.querySelectorAll('iframe')[1].sandbox="
2151 "'allow-scripts');"));
2153 // Check that the current sandbox flags are updated but the effective
2154 // sandbox flags are not.
2155 blink::WebSandboxFlags expected_flags =
2156 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
2157 ~blink::WebSandboxFlags::AutomaticFeatures;
2158 EXPECT_EQ(expected_flags,
2159 root->child_at(1)->current_replication_state().sandbox_flags);
2160 EXPECT_EQ(blink::WebSandboxFlags::None,
2161 root->child_at(1)->effective_sandbox_flags());
2163 // Navigate the second subframe to a page on bar.com. This will trigger a
2164 // remote-to-local frame swap in bar.com's process. The target page has
2165 // another frame, so use TestFrameNavigationObserver to wait for all frames
2166 // to be loaded.
2167 TestFrameNavigationObserver frame_observer(root->child_at(1), 2);
2168 GURL bar_url(embedded_test_server()->GetURL(
2169 "bar.com", "/frame_tree/page_with_one_frame.html"));
2170 NavigateFrameToURL(root->child_at(1), bar_url);
2171 frame_observer.Wait();
2172 EXPECT_EQ(bar_url, root->child_at(1)->current_url());
2173 ASSERT_EQ(1U, root->child_at(1)->child_count());
2175 // Confirm that the browser process has updated the current sandbox flags.
2176 EXPECT_EQ(expected_flags,
2177 root->child_at(1)->current_replication_state().sandbox_flags);
2178 EXPECT_EQ(expected_flags, root->child_at(1)->effective_sandbox_flags());
2180 // Opening a popup in the sandboxed second frame should fail.
2181 bool success = false;
2182 EXPECT_TRUE(
2183 ExecuteScriptAndExtractBool(root->child_at(1)->current_frame_host(),
2184 "window.domAutomationController.send("
2185 "!window.open('data:text/html,dataurl'));",
2186 &success));
2187 EXPECT_TRUE(success);
2188 EXPECT_EQ(1u, Shell::windows().size());
2190 // Make sure that the child frame inherits the sandbox flags of its
2191 // now-sandboxed parent frame.
2192 success = false;
2193 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2194 root->child_at(1)->child_at(0)->current_frame_host(),
2195 "window.domAutomationController.send("
2196 "!window.open('data:text/html,dataurl'));",
2197 &success));
2198 EXPECT_TRUE(success);
2199 EXPECT_EQ(1u, Shell::windows().size());
2202 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
2203 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2204 DynamicSandboxFlagsRendererInitiatedNavigation) {
2205 GURL main_url(
2206 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
2207 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2209 // It is safe to obtain the root frame tree node here, as it doesn't change.
2210 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2211 ->GetFrameTree()
2212 ->root();
2214 TestNavigationObserver observer(shell()->web_contents());
2215 ASSERT_EQ(1U, root->child_count());
2217 // Make sure the frame starts out at the correct cross-site page.
2218 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"),
2219 root->child_at(0)->current_url());
2221 // The frame should not be sandboxed to start with.
2222 EXPECT_EQ(blink::WebSandboxFlags::None,
2223 root->child_at(0)->current_replication_state().sandbox_flags);
2224 EXPECT_EQ(blink::WebSandboxFlags::None,
2225 root->child_at(0)->effective_sandbox_flags());
2227 // Dynamically update the frame's sandbox flags.
2228 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
2229 "window.domAutomationController.send("
2230 "document.querySelector('iframe').sandbox="
2231 "'allow-scripts');"));
2233 // Check that updated sandbox flags are propagated to browser process.
2234 // The new flags should be set in current_replication_state(), while
2235 // effective_sandbox_flags() should still reflect the old flags, because
2236 // sandbox flag updates take place only after navigations. "allow-scripts"
2237 // resets both SandboxFlags::Scripts and SandboxFlags::AutomaticFeatures bits
2238 // per blink::parseSandboxPolicy().
2239 blink::WebSandboxFlags expected_flags =
2240 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
2241 ~blink::WebSandboxFlags::AutomaticFeatures;
2242 EXPECT_EQ(expected_flags,
2243 root->child_at(0)->current_replication_state().sandbox_flags);
2244 EXPECT_EQ(blink::WebSandboxFlags::None,
2245 root->child_at(0)->effective_sandbox_flags());
2247 // Perform a renderer-initiated same-site navigation in the first frame. The
2248 // new sandbox flags should take effect.
2249 TestFrameNavigationObserver frame_observer(root->child_at(0));
2250 ASSERT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
2251 "window.location.href='/title2.html'"));
2252 frame_observer.Wait();
2253 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title2.html"),
2254 root->child_at(0)->current_url());
2256 // Confirm that the browser process has updated the frame's current sandbox
2257 // flags.
2258 EXPECT_EQ(expected_flags,
2259 root->child_at(0)->current_replication_state().sandbox_flags);
2260 EXPECT_EQ(expected_flags, root->child_at(0)->effective_sandbox_flags());
2262 // Opening a popup in the now-sandboxed frame should fail.
2263 bool success = false;
2264 EXPECT_TRUE(
2265 ExecuteScriptAndExtractBool(root->child_at(0)->current_frame_host(),
2266 "window.domAutomationController.send("
2267 "!window.open('data:text/html,dataurl'));",
2268 &success));
2269 EXPECT_TRUE(success);
2270 EXPECT_EQ(1u, Shell::windows().size());
2273 // Verify that when a new child frame is added, the proxies created for it in
2274 // other SiteInstances have correct sandbox flags and origin.
2276 // A A A
2277 // / / \ / \ .
2278 // B -> B A -> B A
2279 // \ .
2280 // B
2282 // The test checks sandbox flags and origin for the proxy added in step 2, by
2283 // checking whether the grandchild frame added in step 3 sees proper sandbox
2284 // flags and origin for its (remote) parent. This wasn't addressed when
2285 // https://crbug.com/423587 was fixed.
2286 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2287 ProxiesForNewChildFramesHaveCorrectReplicationState) {
2288 GURL main_url(
2289 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
2290 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2292 // It is safe to obtain the root frame tree node here, as it doesn't change.
2293 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2294 ->GetFrameTree()
2295 ->root();
2296 TestNavigationObserver observer(shell()->web_contents());
2298 EXPECT_EQ(
2299 " Site A ------------ proxies for B\n"
2300 " +--Site B ------- proxies for A\n"
2301 "Where A = http://127.0.0.1/\n"
2302 " B = http://baz.com/",
2303 DepictFrameTree(root));
2305 // In the root frame, add a new sandboxed local frame, which itself has a
2306 // child frame on baz.com. Wait for three RenderFrameHosts to be created:
2307 // the new sandboxed local frame, its child (while it's still local), and a
2308 // pending RFH when starting the cross-site navigation to baz.com.
2309 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 3);
2310 EXPECT_TRUE(
2311 ExecuteScript(root->current_frame_host(),
2312 "window.domAutomationController.send("
2313 " addFrame('/frame_tree/page_with_one_frame.html',"
2314 " 'allow-scripts allow-same-origin'))"));
2315 frame_observer.Wait();
2317 // Wait for the cross-site navigation to baz.com in the grandchild to finish.
2318 FrameTreeNode* bottom_child = root->child_at(1)->child_at(0);
2319 TestFrameNavigationObserver navigation_observer(bottom_child);
2320 navigation_observer.Wait();
2322 EXPECT_EQ(
2323 " Site A ------------ proxies for B\n"
2324 " |--Site B ------- proxies for A\n"
2325 " +--Site A ------- proxies for B\n"
2326 " +--Site B -- proxies for A\n"
2327 "Where A = http://127.0.0.1/\n"
2328 " B = http://baz.com/",
2329 DepictFrameTree(root));
2331 // Use location.ancestorOrigins to check that the grandchild on baz.com sees
2332 // correct origin for its parent.
2333 int ancestor_origins_length = 0;
2334 EXPECT_TRUE(ExecuteScriptAndExtractInt(
2335 bottom_child->current_frame_host(),
2336 "window.domAutomationController.send(location.ancestorOrigins.length);",
2337 &ancestor_origins_length));
2338 EXPECT_EQ(2, ancestor_origins_length);
2339 std::string parent_origin;
2340 EXPECT_TRUE(ExecuteScriptAndExtractString(
2341 bottom_child->current_frame_host(),
2342 "window.domAutomationController.send(location.ancestorOrigins[0]);",
2343 &parent_origin));
2344 EXPECT_EQ(main_url.GetOrigin().spec(), parent_origin + "/");
2346 // Check that the sandbox flags in the browser process are correct.
2347 // "allow-scripts" resets both WebSandboxFlags::Scripts and
2348 // WebSandboxFlags::AutomaticFeatures bits per blink::parseSandboxPolicy().
2349 blink::WebSandboxFlags expected_flags =
2350 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
2351 ~blink::WebSandboxFlags::AutomaticFeatures &
2352 ~blink::WebSandboxFlags::Origin;
2353 EXPECT_EQ(expected_flags,
2354 root->child_at(1)->current_replication_state().sandbox_flags);
2356 // The child of the sandboxed frame should've inherited sandbox flags, so it
2357 // should not be able to create popups.
2358 bool success = false;
2359 EXPECT_TRUE(
2360 ExecuteScriptAndExtractBool(bottom_child->current_frame_host(),
2361 "window.domAutomationController.send("
2362 "!window.open('data:text/html,dataurl'));",
2363 &success));
2364 EXPECT_TRUE(success);
2365 EXPECT_EQ(1u, Shell::windows().size());
2368 // Verify that a child frame can retrieve the name property set by its parent.
2369 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, WindowNameReplication) {
2370 GURL main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html"));
2371 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2373 // It is safe to obtain the root frame tree node here, as it doesn't change.
2374 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2375 ->GetFrameTree()
2376 ->root();
2378 TestNavigationObserver observer(shell()->web_contents());
2380 // Load cross-site page into iframe.
2381 GURL frame_url =
2382 embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html");
2383 NavigateFrameToURL(root->child_at(0), frame_url);
2384 EXPECT_TRUE(observer.last_navigation_succeeded());
2385 EXPECT_EQ(frame_url, observer.last_navigation_url());
2387 // Ensure that a new process is created for the subframe.
2388 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
2389 root->child_at(0)->current_frame_host()->GetSiteInstance());
2391 // Check that the window.name seen by the frame matches the name attribute
2392 // specified by its parent in the iframe tag.
2393 std::string result;
2394 EXPECT_TRUE(ExecuteScriptAndExtractString(
2395 root->child_at(0)->current_frame_host(),
2396 "window.domAutomationController.send(window.name);", &result));
2397 EXPECT_EQ("3-1-name", result);
2400 // Verify that dynamic updates to a frame's window.name propagate to the
2401 // frame's proxies, so that the latest frame names can be used in navigations.
2402 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicWindowName) {
2403 GURL main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html"));
2404 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2406 // It is safe to obtain the root frame tree node here, as it doesn't change.
2407 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2408 ->GetFrameTree()
2409 ->root();
2410 TestNavigationObserver observer(shell()->web_contents());
2412 // Load cross-site page into iframe.
2413 GURL frame_url =
2414 embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html");
2415 NavigateFrameToURL(root->child_at(0), frame_url);
2416 EXPECT_TRUE(observer.last_navigation_succeeded());
2417 EXPECT_EQ(frame_url, observer.last_navigation_url());
2419 // Browser process should know the child frame's original window.name
2420 // specified in the iframe element.
2421 EXPECT_EQ(root->child_at(0)->frame_name(), "3-1-name");
2423 // Update the child frame's window.name.
2424 EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
2425 "window.domAutomationController.send("
2426 "window.name = 'updated-name');"));
2428 // The change should propagate to the browser process.
2429 EXPECT_EQ(root->child_at(0)->frame_name(), "updated-name");
2431 // The proxy in the parent process should also receive the updated name.
2432 // Check that it can reference the child frame by its new name.
2433 bool success = false;
2434 EXPECT_TRUE(
2435 ExecuteScriptAndExtractBool(shell()->web_contents(),
2436 "window.domAutomationController.send("
2437 "frames['updated-name'] == frames[0]);",
2438 &success));
2439 EXPECT_TRUE(success);
2441 // Issue a renderer-initiated navigation from the root frame to the child
2442 // frame using the frame's name. Make sure correct frame is navigated.
2444 // TODO(alexmos): When blink::createWindow is refactored to handle
2445 // RemoteFrames, this should also be tested via window.open(url, frame_name)
2446 // and a more complicated frame hierarchy (https://crbug.com/463742)
2447 TestFrameNavigationObserver frame_observer(root->child_at(0));
2448 GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
2449 std::string script = base::StringPrintf(
2450 "window.domAutomationController.send("
2451 "frames['updated-name'].location.href = '%s');",
2452 foo_url.spec().c_str());
2453 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), script));
2454 frame_observer.Wait();
2455 EXPECT_EQ(foo_url, root->child_at(0)->current_url());
2458 // Verify that when a frame is navigated to a new origin, the origin update
2459 // propagates to the frame's proxies.
2460 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OriginUpdatesReachProxies) {
2461 GURL main_url(
2462 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
2463 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2465 // It is safe to obtain the root frame tree node here, as it doesn't change.
2466 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2467 ->GetFrameTree()
2468 ->root();
2469 TestNavigationObserver observer(shell()->web_contents());
2471 EXPECT_EQ(
2472 " Site A ------------ proxies for B\n"
2473 " |--Site B ------- proxies for A\n"
2474 " +--Site A ------- proxies for B\n"
2475 "Where A = http://127.0.0.1/\n"
2476 " B = http://bar.com/",
2477 DepictFrameTree(root));
2479 // Navigate second subframe to a baz.com. This should send an origin update
2480 // to the frame's proxy in the bar.com (first frame's) process.
2481 GURL frame_url = embedded_test_server()->GetURL("baz.com", "/title2.html");
2482 NavigateFrameToURL(root->child_at(1), frame_url);
2483 EXPECT_TRUE(observer.last_navigation_succeeded());
2484 EXPECT_EQ(frame_url, observer.last_navigation_url());
2486 // The first frame can't directly observe the second frame's origin with
2487 // JavaScript. Instead, try to navigate the second frame from the first
2488 // frame. This should fail with a console error message, which should
2489 // contain the second frame's updated origin (see blink::Frame::canNavigate).
2490 scoped_ptr<ConsoleObserverDelegate> console_delegate(
2491 new ConsoleObserverDelegate(
2492 shell()->web_contents(),
2493 "Unsafe JavaScript attempt to initiate navigation*"));
2494 shell()->web_contents()->SetDelegate(console_delegate.get());
2496 // frames[1] can't be used due to a bug where RemoteFrames are created out of
2497 // order (https://crbug.com/478792). Instead, target second frame by name.
2498 EXPECT_TRUE(ExecuteScript(
2499 root->child_at(0)->current_frame_host(),
2500 "window.domAutomationController.send("
2501 " parent.frames['frame2'].location.href = 'data:text/html,foo');"));
2502 console_delegate->Wait();
2504 std::string frame_origin =
2505 root->child_at(1)->current_replication_state().origin.Serialize();
2506 EXPECT_EQ(frame_origin + "/", frame_url.GetOrigin().spec());
2507 EXPECT_TRUE(
2508 base::MatchPattern(console_delegate->message(), "*" + frame_origin + "*"))
2509 << "Error message does not contain the frame's latest origin ("
2510 << frame_origin << ")";
2513 // Ensure that navigating subframes in --site-per-process mode properly fires
2514 // the DidStopLoading event on WebContentsObserver.
2515 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteDidStopLoading) {
2516 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
2517 NavigateToURL(shell(), main_url);
2519 // It is safe to obtain the root frame tree node here, as it doesn't change.
2520 FrameTreeNode* root =
2521 static_cast<WebContentsImpl*>(shell()->web_contents())->
2522 GetFrameTree()->root();
2524 TestNavigationObserver observer(shell()->web_contents());
2526 // Load same-site page into iframe.
2527 FrameTreeNode* child = root->child_at(0);
2528 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
2529 NavigateFrameToURL(child, http_url);
2530 EXPECT_EQ(http_url, observer.last_navigation_url());
2531 EXPECT_TRUE(observer.last_navigation_succeeded());
2533 // Load cross-site page into iframe.
2534 TestNavigationObserver nav_observer(shell()->web_contents(), 1);
2535 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
2536 NavigationController::LoadURLParams params(url);
2537 params.transition_type = ui::PAGE_TRANSITION_LINK;
2538 params.frame_tree_node_id = child->frame_tree_node_id();
2539 child->navigator()->GetController()->LoadURLWithParams(params);
2540 nav_observer.Wait();
2542 // Verify that the navigation succeeded and the expected URL was loaded.
2543 EXPECT_TRUE(observer.last_navigation_succeeded());
2544 EXPECT_EQ(url, observer.last_navigation_url());
2547 // Ensure that the renderer does not crash when navigating a frame that has a
2548 // sibling RemoteFrame. See https://crbug.com/426953.
2549 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2550 NavigateWithSiblingRemoteFrame) {
2551 GURL main_url(
2552 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
2553 NavigateToURL(shell(), main_url);
2555 // It is safe to obtain the root frame tree node here, as it doesn't change.
2556 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2557 ->GetFrameTree()
2558 ->root();
2559 TestNavigationObserver observer(shell()->web_contents());
2561 // Make sure the first frame is out of process.
2562 ASSERT_EQ(2U, root->child_count());
2563 FrameTreeNode* node2 = root->child_at(0);
2564 EXPECT_NE(root->current_frame_host()->GetSiteInstance(),
2565 node2->current_frame_host()->GetSiteInstance());
2567 // Make sure the second frame is in the parent's process.
2568 FrameTreeNode* node3 = root->child_at(1);
2569 EXPECT_EQ(root->current_frame_host()->GetSiteInstance(),
2570 node3->current_frame_host()->GetSiteInstance());
2572 // Navigate the second iframe (node3) to a URL in its own process.
2573 GURL title_url = embedded_test_server()->GetURL("/title2.html");
2574 NavigateFrameToURL(node3, title_url);
2575 EXPECT_TRUE(observer.last_navigation_succeeded());
2576 EXPECT_EQ(title_url, observer.last_navigation_url());
2577 EXPECT_EQ(root->current_frame_host()->GetSiteInstance(),
2578 node3->current_frame_host()->GetSiteInstance());
2579 EXPECT_TRUE(node3->current_frame_host()->IsRenderFrameLive());
2582 // Verify that load events for iframe elements work when the child frame is
2583 // out-of-process. In such cases, the load event is forwarded from the child
2584 // frame to the parent frame via the browser process.
2585 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, LoadEventForwarding) {
2586 // Load a page with a cross-site frame. The parent page has an onload
2587 // handler in the iframe element that appends "LOADED" to the document title.
2589 GURL main_url(
2590 embedded_test_server()->GetURL("/frame_with_load_event.html"));
2591 base::string16 expected_title(base::UTF8ToUTF16("LOADED"));
2592 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
2593 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2594 EXPECT_EQ(title_watcher.WaitAndGetTitle(), expected_title);
2597 // It is safe to obtain the root frame tree node here, as it doesn't change.
2598 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2599 ->GetFrameTree()
2600 ->root();
2602 // Load another cross-site page into the iframe and check that the load event
2603 // is fired.
2605 GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
2606 base::string16 expected_title(base::UTF8ToUTF16("LOADEDLOADED"));
2607 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
2608 TestNavigationObserver observer(shell()->web_contents());
2609 NavigateFrameToURL(root->child_at(0), foo_url);
2610 EXPECT_TRUE(observer.last_navigation_succeeded());
2611 EXPECT_EQ(foo_url, observer.last_navigation_url());
2612 EXPECT_EQ(title_watcher.WaitAndGetTitle(), expected_title);
2616 // Check that postMessage can be routed between cross-site iframes.
2617 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SubframePostMessage) {
2618 GURL main_url(embedded_test_server()->GetURL(
2619 "/frame_tree/page_with_post_message_frames.html"));
2620 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2622 // It is safe to obtain the root frame tree node here, as it doesn't change.
2623 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2624 ->GetFrameTree()
2625 ->root();
2627 ASSERT_EQ(2U, root->child_count());
2629 // Verify the frames start at correct URLs. First frame should be
2630 // same-site; second frame should be cross-site.
2631 GURL same_site_url(embedded_test_server()->GetURL("/post_message.html"));
2632 EXPECT_EQ(same_site_url, root->child_at(0)->current_url());
2633 GURL foo_url(embedded_test_server()->GetURL("foo.com",
2634 "/post_message.html"));
2635 EXPECT_EQ(foo_url, root->child_at(1)->current_url());
2636 EXPECT_NE(root->child_at(0)->current_frame_host()->GetSiteInstance(),
2637 root->child_at(1)->current_frame_host()->GetSiteInstance());
2639 // Send a message from first, same-site frame to second, cross-site frame.
2640 // Expect the second frame to reply back to the first frame.
2641 PostMessageAndWaitForReply(root->child_at(0),
2642 "postToSibling('subframe-msg','subframe2')",
2643 "\"done-subframe1\"");
2645 // Send a postMessage from second, cross-site frame to its parent. Expect
2646 // parent to send a reply to the frame.
2647 base::string16 expected_title(base::ASCIIToUTF16("subframe-msg"));
2648 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
2649 PostMessageAndWaitForReply(root->child_at(1), "postToParent('subframe-msg')",
2650 "\"done-subframe2\"");
2651 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
2653 // Verify the total number of received messages for each subframe. First
2654 // frame should have one message (reply from second frame). Second frame
2655 // should have two messages (message from first frame and reply from parent).
2656 // Parent should have one message (from second frame).
2657 EXPECT_EQ(1, GetReceivedMessages(root->child_at(0)));
2658 EXPECT_EQ(2, GetReceivedMessages(root->child_at(1)));
2659 EXPECT_EQ(1, GetReceivedMessages(root));
2662 // Check that postMessage can be sent from a subframe on a cross-process opener
2663 // tab, and that its event.source points to a valid proxy.
2664 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2665 PostMessageWithSubframeOnOpenerChain) {
2666 GURL main_url(embedded_test_server()->GetURL(
2667 "a.com", "/frame_tree/page_with_post_message_frames.html"));
2668 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2670 // It is safe to obtain the root frame tree node here, as it doesn't change.
2671 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2672 ->GetFrameTree()
2673 ->root();
2675 ASSERT_EQ(2U, root->child_count());
2677 // Verify the initial state of the world. First frame should be same-site;
2678 // second frame should be cross-site.
2679 EXPECT_EQ(
2680 " Site A ------------ proxies for B\n"
2681 " |--Site A ------- proxies for B\n"
2682 " +--Site B ------- proxies for A\n"
2683 "Where A = http://a.com/\n"
2684 " B = http://foo.com/",
2685 DepictFrameTree(root));
2687 // Open a popup from the first subframe (so that popup's window.opener points
2688 // to the subframe) and navigate it to bar.com.
2689 ShellAddedObserver new_shell_observer;
2690 EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
2691 "openPopup('about:blank');"));
2692 Shell* popup = new_shell_observer.GetShell();
2693 GURL popup_url(
2694 embedded_test_server()->GetURL("bar.com", "/post_message.html"));
2695 EXPECT_TRUE(NavigateToURL(popup, popup_url));
2697 // From the popup, open another popup for baz.com. This will be used to
2698 // check that the whole opener chain is processed when creating proxies and
2699 // not just an immediate opener.
2700 ShellAddedObserver new_shell_observer2;
2701 EXPECT_TRUE(
2702 ExecuteScript(popup->web_contents(), "openPopup('about:blank');"));
2703 Shell* popup2 = new_shell_observer2.GetShell();
2704 GURL popup2_url(
2705 embedded_test_server()->GetURL("baz.com", "/post_message.html"));
2706 EXPECT_TRUE(NavigateToURL(popup2, popup2_url));
2708 // Ensure that we've created proxies for SiteInstances of both popups (C, D)
2709 // in the main window's frame tree.
2710 EXPECT_EQ(
2711 " Site A ------------ proxies for B C D\n"
2712 " |--Site A ------- proxies for B C D\n"
2713 " +--Site B ------- proxies for A C D\n"
2714 "Where A = http://a.com/\n"
2715 " B = http://foo.com/\n"
2716 " C = http://bar.com/\n"
2717 " D = http://baz.com/",
2718 DepictFrameTree(root));
2720 // Check the first popup's frame tree as well. Note that it doesn't have a
2721 // proxy for foo.com, since foo.com can't reach the popup. It does have a
2722 // proxy for its opener a.com (which can reach it via the window.open
2723 // reference) and second popup (which can reach it via window.opener).
2724 FrameTreeNode* popup_root =
2725 static_cast<WebContentsImpl*>(popup->web_contents())
2726 ->GetFrameTree()
2727 ->root();
2728 EXPECT_EQ(
2729 " Site C ------------ proxies for A D\n"
2730 "Where A = http://a.com/\n"
2731 " C = http://bar.com/\n"
2732 " D = http://baz.com/",
2733 DepictFrameTree(popup_root));
2735 // Send a message from first subframe on main page to the first popup and
2736 // wait for a reply back. The reply verifies that the proxy for the opener
2737 // tab's subframe is targeted properly.
2738 PostMessageAndWaitForReply(root->child_at(0), "postToPopup('subframe-msg')",
2739 "\"done-subframe1\"");
2741 // Send a postMessage from the popup to window.opener and ensure that it
2742 // reaches subframe1. This verifies that the subframe opener information
2743 // propagated to the popup's RenderFrame. Wait for subframe1 to send a reply
2744 // message to the popup.
2745 EXPECT_TRUE(ExecuteScript(popup->web_contents(), "window.name = 'popup';"));
2746 PostMessageAndWaitForReply(popup_root, "postToOpener('subframe-msg', '*')",
2747 "\"done-popup\"");
2749 // Second a postMessage from popup2 to window.opener.opener, which should
2750 // resolve to subframe1. This tests opener chains of length greater than 1.
2751 // As before, subframe1 will send a reply to popup2.
2752 FrameTreeNode* popup2_root =
2753 static_cast<WebContentsImpl*>(popup2->web_contents())
2754 ->GetFrameTree()
2755 ->root();
2756 EXPECT_TRUE(ExecuteScript(popup2->web_contents(), "window.name = 'popup2';"));
2757 PostMessageAndWaitForReply(popup2_root,
2758 "postToOpenerOfOpener('subframe-msg', '*')",
2759 "\"done-popup2\"");
2761 // Verify the total number of received messages for each subframe:
2762 // - 3 for first subframe (two from first popup, one from second popup)
2763 // - 2 for popup (both from first subframe)
2764 // - 1 for popup2 (reply from first subframe)
2765 // - 0 for other frames
2766 EXPECT_EQ(0, GetReceivedMessages(root));
2767 EXPECT_EQ(3, GetReceivedMessages(root->child_at(0)));
2768 EXPECT_EQ(0, GetReceivedMessages(root->child_at(1)));
2769 EXPECT_EQ(2, GetReceivedMessages(popup_root));
2770 EXPECT_EQ(1, GetReceivedMessages(popup2_root));
2773 // Check that parent.frames[num] references correct sibling frames when the
2774 // parent is remote. See https://crbug.com/478792.
2775 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, IndexedFrameAccess) {
2776 // Start on a page with three same-site subframes.
2777 GURL main_url(
2778 embedded_test_server()->GetURL("a.com", "/frame_tree/top.html"));
2779 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2781 // It is safe to obtain the root frame tree node here, as it doesn't change.
2782 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2783 ->GetFrameTree()
2784 ->root();
2785 ASSERT_EQ(3U, root->child_count());
2786 FrameTreeNode* child0 = root->child_at(0);
2787 FrameTreeNode* child1 = root->child_at(1);
2788 FrameTreeNode* child2 = root->child_at(2);
2790 // Send each of the frames to a different site. Each new renderer will first
2791 // create proxies for the parent and two sibling subframes and then create
2792 // and insert the new RenderFrame into the frame tree.
2793 GURL b_url(embedded_test_server()->GetURL("b.com", "/post_message.html"));
2794 GURL c_url(embedded_test_server()->GetURL("c.com", "/post_message.html"));
2795 GURL d_url(embedded_test_server()->GetURL("d.com", "/post_message.html"));
2796 NavigateFrameToURL(child0, b_url);
2797 // TODO(alexmos): The calls to WaitForRenderFrameReady can be removed once
2798 // TestFrameNavigationObserver is fixed to use DidFinishLoad.
2799 EXPECT_TRUE(WaitForRenderFrameReady(child0->current_frame_host()));
2800 NavigateFrameToURL(child1, c_url);
2801 EXPECT_TRUE(WaitForRenderFrameReady(child1->current_frame_host()));
2802 NavigateFrameToURL(child2, d_url);
2803 EXPECT_TRUE(WaitForRenderFrameReady(child2->current_frame_host()));
2805 EXPECT_EQ(
2806 " Site A ------------ proxies for B C D\n"
2807 " |--Site B ------- proxies for A C D\n"
2808 " |--Site C ------- proxies for A B D\n"
2809 " +--Site D ------- proxies for A B C\n"
2810 "Where A = http://a.com/\n"
2811 " B = http://b.com/\n"
2812 " C = http://c.com/\n"
2813 " D = http://d.com/",
2814 DepictFrameTree(root));
2816 // Check that each subframe sees itself at correct index in parent.frames.
2817 bool success = false;
2818 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2819 child0->current_frame_host(),
2820 "window.domAutomationController.send(window === parent.frames[0]);",
2821 &success));
2822 EXPECT_TRUE(success);
2824 success = false;
2825 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2826 child1->current_frame_host(),
2827 "window.domAutomationController.send(window === parent.frames[1]);",
2828 &success));
2829 EXPECT_TRUE(success);
2831 success = false;
2832 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2833 child2->current_frame_host(),
2834 "window.domAutomationController.send(window === parent.frames[2]);",
2835 &success));
2836 EXPECT_TRUE(success);
2838 // Send a postMessage from B to parent.frames[1], which should go to C, and
2839 // wait for reply.
2840 PostMessageAndWaitForReply(child0, "postToSibling('subframe-msg', 1)",
2841 "\"done-1-1-name\"");
2843 // Send a postMessage from C to parent.frames[2], which should go to D, and
2844 // wait for reply.
2845 PostMessageAndWaitForReply(child1, "postToSibling('subframe-msg', 2)",
2846 "\"done-1-2-name\"");
2848 // Verify the total number of received messages for each subframe.
2849 EXPECT_EQ(1, GetReceivedMessages(child0));
2850 EXPECT_EQ(2, GetReceivedMessages(child1));
2851 EXPECT_EQ(1, GetReceivedMessages(child2));
2854 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, RFPHDestruction) {
2855 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
2856 NavigateToURL(shell(), main_url);
2858 // It is safe to obtain the root frame tree node here, as it doesn't change.
2859 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2860 ->GetFrameTree()
2861 ->root();
2863 TestNavigationObserver observer(shell()->web_contents());
2865 // Load cross-site page into iframe.
2866 FrameTreeNode* child = root->child_at(0);
2867 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
2868 NavigateFrameToURL(root->child_at(0), url);
2869 EXPECT_TRUE(observer.last_navigation_succeeded());
2870 EXPECT_EQ(url, observer.last_navigation_url());
2871 EXPECT_EQ(
2872 " Site A ------------ proxies for B\n"
2873 " |--Site B ------- proxies for A\n"
2874 " +--Site A ------- proxies for B\n"
2875 " |--Site A -- proxies for B\n"
2876 " +--Site A -- proxies for B\n"
2877 " +--Site A -- proxies for B\n"
2878 "Where A = http://127.0.0.1/\n"
2879 " B = http://foo.com/",
2880 DepictFrameTree(root));
2882 // Load another cross-site page.
2883 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
2884 NavigateIframeToURL(shell()->web_contents(), "test", url);
2885 EXPECT_TRUE(observer.last_navigation_succeeded());
2886 EXPECT_EQ(url, observer.last_navigation_url());
2887 EXPECT_EQ(
2888 " Site A ------------ proxies for C\n"
2889 " |--Site C ------- proxies for A\n"
2890 " +--Site A ------- proxies for C\n"
2891 " |--Site A -- proxies for C\n"
2892 " +--Site A -- proxies for C\n"
2893 " +--Site A -- proxies for C\n"
2894 "Where A = http://127.0.0.1/\n"
2895 " C = http://bar.com/",
2896 DepictFrameTree(root));
2898 // Navigate back to the parent's origin.
2899 url = embedded_test_server()->GetURL("/title1.html");
2900 NavigateFrameToURL(child, url);
2901 EXPECT_EQ(url, observer.last_navigation_url());
2902 EXPECT_TRUE(observer.last_navigation_succeeded());
2903 EXPECT_EQ(
2904 " Site A\n"
2905 " |--Site A\n"
2906 " +--Site A\n"
2907 " |--Site A\n"
2908 " +--Site A\n"
2909 " +--Site A\n"
2910 "Where A = http://127.0.0.1/",
2911 DepictFrameTree(root));
2914 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OpenPopupWithRemoteParent) {
2915 GURL main_url(
2916 embedded_test_server()->GetURL("a.com", "/site_per_process_main.html"));
2917 NavigateToURL(shell(), main_url);
2919 // It is safe to obtain the root frame tree node here, as it doesn't change.
2920 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2921 ->GetFrameTree()
2922 ->root();
2924 // Navigate first child cross-site.
2925 GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
2926 NavigateFrameToURL(root->child_at(0), frame_url);
2928 // Open a popup from the first child.
2929 Shell* new_shell = OpenPopup(root->child_at(0)->current_frame_host(),
2930 GURL(url::kAboutBlankURL), "");
2931 EXPECT_TRUE(new_shell);
2933 // Check that the popup's opener is correct on both the browser and renderer
2934 // sides.
2935 FrameTreeNode* popup_root =
2936 static_cast<WebContentsImpl*>(new_shell->web_contents())
2937 ->GetFrameTree()
2938 ->root();
2939 EXPECT_EQ(root->child_at(0), popup_root->opener());
2941 std::string opener_url;
2942 EXPECT_TRUE(ExecuteScriptAndExtractString(
2943 popup_root->current_frame_host(),
2944 "window.domAutomationController.send(window.opener.location.href);",
2945 &opener_url));
2946 EXPECT_EQ(frame_url.spec(), opener_url);
2948 // Now try the same with a cross-site popup and make sure it ends up in a new
2949 // process and with a correct opener.
2950 GURL popup_url(embedded_test_server()->GetURL("c.com", "/title2.html"));
2951 Shell* cross_site_popup =
2952 OpenPopup(root->child_at(0)->current_frame_host(), popup_url, "");
2953 EXPECT_TRUE(cross_site_popup);
2955 FrameTreeNode* cross_site_popup_root =
2956 static_cast<WebContentsImpl*>(cross_site_popup->web_contents())
2957 ->GetFrameTree()
2958 ->root();
2959 EXPECT_EQ(cross_site_popup_root->current_url(), popup_url);
2961 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
2962 cross_site_popup->web_contents()->GetSiteInstance());
2963 EXPECT_NE(root->child_at(0)->current_frame_host()->GetSiteInstance(),
2964 cross_site_popup->web_contents()->GetSiteInstance());
2966 EXPECT_EQ(root->child_at(0), cross_site_popup_root->opener());
2968 // Ensure the popup's window.opener points to the right subframe. Note that
2969 // we can't check the opener's location as above since it's cross-origin.
2970 bool success = false;
2971 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2972 cross_site_popup_root->current_frame_host(),
2973 "window.domAutomationController.send("
2974 " window.opener === window.opener.top.frames[0]);",
2975 &success));
2976 EXPECT_TRUE(success);
2979 // Verify that named frames are discoverable from their opener's ancestors.
2980 // See https://crbug.com/511474.
2981 // Disable this flaky test on the official cros-trunk for now.
2982 // See crbug.com/515302.
2983 #if defined(OFFICIAL_BUILD)
2984 #define MAYBE_DiscoverNamedFrameFromAncestorOfOpener \
2985 DISABLED_DiscoverNamedFrameFromAncestorOfOpener
2986 #else
2987 #define MAYBE_DiscoverNamedFrameFromAncestorOfOpener \
2988 DiscoverNamedFrameFromAncestorOfOpener
2989 #endif // defined(OFFICIAL_BUILD)
2990 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2991 MAYBE_DiscoverNamedFrameFromAncestorOfOpener) {
2992 GURL main_url(
2993 embedded_test_server()->GetURL("a.com", "/site_per_process_main.html"));
2994 NavigateToURL(shell(), main_url);
2996 // It is safe to obtain the root frame tree node here, as it doesn't change.
2997 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2998 ->GetFrameTree()
2999 ->root();
3001 // Navigate first child cross-site.
3002 GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
3003 NavigateFrameToURL(root->child_at(0), frame_url);
3005 // Open a popup named "foo" from the first child.
3006 Shell* foo_shell = OpenPopup(root->child_at(0)->current_frame_host(),
3007 GURL(url::kAboutBlankURL), "foo");
3008 EXPECT_TRUE(foo_shell);
3010 // Check that a proxy was created for the "foo" popup in a.com.
3011 FrameTreeNode* foo_root =
3012 static_cast<WebContentsImpl*>(foo_shell->web_contents())
3013 ->GetFrameTree()
3014 ->root();
3015 SiteInstance* site_instance_a = root->current_frame_host()->GetSiteInstance();
3016 RenderFrameProxyHost* popup_rfph_for_a =
3017 foo_root->render_manager()->GetRenderFrameProxyHost(site_instance_a);
3018 EXPECT_TRUE(popup_rfph_for_a);
3020 // Verify that the main frame can find the "foo" popup by name. If
3021 // window.open targets the correct frame, the "foo" popup's current URL
3022 // should be updated to |named_frame_url|.
3023 GURL named_frame_url(embedded_test_server()->GetURL("c.com", "/title2.html"));
3024 NavigateNamedFrame(shell()->web_contents(), named_frame_url, "foo");
3025 EXPECT_TRUE(WaitForLoadStop(foo_shell->web_contents()));
3026 EXPECT_EQ(named_frame_url, foo_root->current_url());
3028 // Navigate the popup cross-site and ensure it's still reachable via
3029 // window.open from the main frame.
3030 GURL d_url(embedded_test_server()->GetURL("d.com", "/title3.html"));
3031 NavigateToURL(foo_shell, d_url);
3032 EXPECT_EQ(d_url, foo_root->current_url());
3033 NavigateNamedFrame(shell()->web_contents(), named_frame_url, "foo");
3034 EXPECT_TRUE(WaitForLoadStop(foo_shell->web_contents()));
3035 EXPECT_EQ(named_frame_url, foo_root->current_url());
3038 // Similar to DiscoverNamedFrameFromAncestorOfOpener, but check that if a
3039 // window is created without a name and acquires window.name later, it will
3040 // still be discoverable from its opener's ancestors. Also, instead of using
3041 // an opener's ancestor, this test uses a popup with same origin as that
3042 // ancestor. See https://crbug.com/511474.
3043 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
3044 DiscoverFrameAfterSettingWindowName) {
3045 GURL main_url(
3046 embedded_test_server()->GetURL("a.com", "/site_per_process_main.html"));
3047 NavigateToURL(shell(), main_url);
3049 // It is safe to obtain the root frame tree node here, as it doesn't change.
3050 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
3051 ->GetFrameTree()
3052 ->root();
3054 // Open a same-site popup from the main frame.
3055 GURL a_com_url(embedded_test_server()->GetURL("a.com", "/title3.html"));
3056 Shell* a_com_shell =
3057 OpenPopup(root->child_at(0)->current_frame_host(), a_com_url, "");
3058 EXPECT_TRUE(a_com_shell);
3060 // Navigate first child on main frame cross-site.
3061 GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
3062 NavigateFrameToURL(root->child_at(0), frame_url);
3064 // Open an unnamed popup from the first child frame.
3065 Shell* foo_shell = OpenPopup(root->child_at(0)->current_frame_host(),
3066 GURL(url::kAboutBlankURL), "");
3067 EXPECT_TRUE(foo_shell);
3069 // There should be no proxy created for the "foo" popup in a.com, since
3070 // there's no way for the two a.com frames to access it yet.
3071 FrameTreeNode* foo_root =
3072 static_cast<WebContentsImpl*>(foo_shell->web_contents())
3073 ->GetFrameTree()
3074 ->root();
3075 SiteInstance* site_instance_a = root->current_frame_host()->GetSiteInstance();
3076 EXPECT_FALSE(
3077 foo_root->render_manager()->GetRenderFrameProxyHost(site_instance_a));
3079 // Set window.name in the popup's frame.
3080 EXPECT_TRUE(ExecuteScript(foo_shell->web_contents(), "window.name = 'foo'"));
3082 // A proxy for the popup should now exist in a.com.
3083 EXPECT_TRUE(
3084 foo_root->render_manager()->GetRenderFrameProxyHost(site_instance_a));
3086 // Verify that the a.com popup can now find the "foo" popup by name.
3087 GURL named_frame_url(embedded_test_server()->GetURL("c.com", "/title2.html"));
3088 NavigateNamedFrame(a_com_shell->web_contents(), named_frame_url, "foo");
3089 EXPECT_TRUE(WaitForLoadStop(foo_shell->web_contents()));
3090 EXPECT_EQ(named_frame_url, foo_root->current_url());
3093 // Check that frame opener updates work with subframes. Set up a window with a
3094 // popup and update openers for the popup's main frame and subframe to
3095 // subframes on first window, as follows:
3097 // foo +---- bar
3098 // / \ | / \ .
3099 // bar foo <-+ bar foo
3100 // ^ |
3101 // +--------------------+
3103 // The sites are carefully set up so that both opener updates are cross-process
3104 // but still allowed by Blink's navigation checks.
3105 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, UpdateSubframeOpener) {
3106 GURL main_url = embedded_test_server()->GetURL(
3107 "foo.com", "/frame_tree/page_with_two_frames.html");
3108 EXPECT_TRUE(NavigateToURL(shell(), main_url));
3110 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
3111 ->GetFrameTree()
3112 ->root();
3113 EXPECT_EQ(2U, root->child_count());
3115 // From the top frame, open a popup and navigate it to a cross-site page with
3116 // two subframes.
3117 Shell* popup_shell =
3118 OpenPopup(shell()->web_contents(), GURL(url::kAboutBlankURL), "popup");
3119 EXPECT_TRUE(popup_shell);
3120 GURL popup_url(embedded_test_server()->GetURL(
3121 "bar.com", "/frame_tree/page_with_post_message_frames.html"));
3122 NavigateToURL(popup_shell, popup_url);
3124 FrameTreeNode* popup_root =
3125 static_cast<WebContentsImpl*>(popup_shell->web_contents())
3126 ->GetFrameTree()
3127 ->root();
3128 EXPECT_EQ(2U, popup_root->child_count());
3130 // Popup's opener should point to main frame to start with.
3131 EXPECT_EQ(root, popup_root->opener());
3133 // Update the popup's opener to the second subframe on the main page (which
3134 // is same-origin with the top frame, i.e., foo.com).
3135 bool success = false;
3136 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3137 root->child_at(1)->current_frame_host(),
3138 "window.domAutomationController.send(!!window.open('','popup'));",
3139 &success));
3140 EXPECT_TRUE(success);
3142 // Check that updated opener propagated to the browser process and the
3143 // popup's bar.com process.
3144 EXPECT_EQ(root->child_at(1), popup_root->opener());
3146 success = false;
3147 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3148 popup_shell->web_contents(),
3149 "window.domAutomationController.send("
3150 " window.opener === window.opener.parent.frames['frame2']);",
3151 &success));
3152 EXPECT_TRUE(success);
3154 // Now update opener on the popup's second subframe (foo.com) to the main
3155 // page's first subframe (bar.com).
3156 success = false;
3157 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3158 root->child_at(0)->current_frame_host(),
3159 "window.domAutomationController.send(!!window.open('','subframe2'));",
3160 &success));
3161 EXPECT_TRUE(success);
3163 // Check that updated opener propagated to the browser process and the
3164 // foo.com process.
3165 EXPECT_EQ(root->child_at(0), popup_root->child_at(1)->opener());
3167 success = false;
3168 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3169 popup_root->child_at(1)->current_frame_host(),
3170 "window.domAutomationController.send("
3171 " window.opener === window.opener.parent.frames['frame1']);",
3172 &success));
3173 EXPECT_TRUE(success);
3176 // Check that when a subframe navigates to a new SiteInstance, the new
3177 // SiteInstance will get a proxy for the opener of subframe's parent. I.e.,
3178 // accessing parent.opener from the subframe should still work after a
3179 // cross-process navigation.
3180 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
3181 NavigatingSubframePreservesOpenerInParent) {
3182 GURL main_url = embedded_test_server()->GetURL("a.com", "/post_message.html");
3183 EXPECT_TRUE(NavigateToURL(shell(), main_url));
3185 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
3186 ->GetFrameTree()
3187 ->root();
3189 // Open a popup with a cross-site page that has a subframe.
3190 GURL popup_url(embedded_test_server()->GetURL(
3191 "b.com", "/cross_site_iframe_factory.html?b(b)"));
3192 Shell* popup_shell = OpenPopup(shell()->web_contents(), popup_url, "popup");
3193 EXPECT_TRUE(popup_shell);
3194 FrameTreeNode* popup_root =
3195 static_cast<WebContentsImpl*>(popup_shell->web_contents())
3196 ->GetFrameTree()
3197 ->root();
3198 EXPECT_EQ(1U, popup_root->child_count());
3200 // Check that the popup's opener is correct in the browser process.
3201 EXPECT_EQ(root, popup_root->opener());
3203 // Navigate popup's subframe to another site.
3204 GURL frame_url(embedded_test_server()->GetURL("c.com", "/post_message.html"));
3205 NavigateFrameToURL(popup_root->child_at(0), frame_url);
3206 EXPECT_TRUE(
3207 WaitForRenderFrameReady(popup_root->child_at(0)->current_frame_host()));
3209 // Check that the new subframe process still sees correct opener for its
3210 // parent by sending a postMessage to subframe's parent.opener.
3211 bool success = false;
3212 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3213 popup_root->child_at(0)->current_frame_host(),
3214 "window.domAutomationController.send(!!parent.opener);", &success));
3215 EXPECT_TRUE(success);
3217 base::string16 expected_title = base::ASCIIToUTF16("msg");
3218 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
3219 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3220 popup_root->child_at(0)->current_frame_host(),
3221 "window.domAutomationController.send(postToOpenerOfParent('msg','*'));",
3222 &success));
3223 EXPECT_TRUE(success);
3224 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
3227 // Check that if a subframe has an opener, that opener is preserved when the
3228 // subframe navigates cross-site.
3229 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NavigateSubframeWithOpener) {
3230 GURL main_url(embedded_test_server()->GetURL(
3231 "foo.com", "/frame_tree/page_with_two_frames.html"));
3232 EXPECT_TRUE(NavigateToURL(shell(), main_url));
3234 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
3235 ->GetFrameTree()
3236 ->root();
3237 EXPECT_EQ(
3238 " Site A ------------ proxies for B\n"
3239 " |--Site B ------- proxies for A\n"
3240 " +--Site A ------- proxies for B\n"
3241 "Where A = http://foo.com/\n"
3242 " B = http://bar.com/",
3243 DepictFrameTree(root));
3245 // Update the first (cross-site) subframe's opener to root frame.
3246 bool success = false;
3247 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3248 root->current_frame_host(),
3249 "window.domAutomationController.send(!!window.open('','frame1'));",
3250 &success));
3251 EXPECT_TRUE(success);
3253 // Check that updated opener propagated to the browser process and subframe's
3254 // process.
3255 EXPECT_EQ(root, root->child_at(0)->opener());
3257 success = false;
3258 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3259 root->child_at(0)->current_frame_host(),
3260 "window.domAutomationController.send(window.opener === window.parent);",
3261 &success));
3262 EXPECT_TRUE(success);
3264 // Navigate the subframe with opener to another site.
3265 GURL frame_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
3266 NavigateFrameToURL(root->child_at(0), frame_url);
3268 // Check that the subframe still sees correct opener in its new process.
3269 success = false;
3270 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3271 root->child_at(0)->current_frame_host(),
3272 "window.domAutomationController.send(window.opener === window.parent);",
3273 &success));
3274 EXPECT_TRUE(success);
3276 // Navigate second subframe to a new site. Check that the proxy that's
3277 // created for the first subframe in the new SiteInstance has correct opener.
3278 GURL frame2_url(embedded_test_server()->GetURL("qux.com", "/title1.html"));
3279 NavigateFrameToURL(root->child_at(1), frame2_url);
3281 success = false;
3282 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3283 root->child_at(1)->current_frame_host(),
3284 "window.domAutomationController.send("
3285 " parent.frames['frame1'].opener === parent);",
3286 &success));
3287 EXPECT_TRUE(success);
3290 // Check that if a subframe has an opener, that opener is preserved when a new
3291 // RenderFrameProxy is created for that subframe in another renderer process.
3292 // Similar to NavigateSubframeWithOpener, but this test verifies the subframe
3293 // opener plumbing for FrameMsg_NewFrameProxy, whereas
3294 // NavigateSubframeWithOpener targets FrameMsg_NewFrame.
3295 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
3296 NewRenderFrameProxyPreservesOpener) {
3297 GURL main_url(
3298 embedded_test_server()->GetURL("foo.com", "/post_message.html"));
3299 EXPECT_TRUE(NavigateToURL(shell(), main_url));
3301 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
3302 ->GetFrameTree()
3303 ->root();
3305 // Open a popup with a cross-site page that has two subframes.
3306 GURL popup_url(embedded_test_server()->GetURL(
3307 "bar.com", "/frame_tree/page_with_post_message_frames.html"));
3308 Shell* popup_shell = OpenPopup(shell()->web_contents(), popup_url, "popup");
3309 EXPECT_TRUE(popup_shell);
3310 FrameTreeNode* popup_root =
3311 static_cast<WebContentsImpl*>(popup_shell->web_contents())
3312 ->GetFrameTree()
3313 ->root();
3314 EXPECT_EQ(
3315 " Site A ------------ proxies for B\n"
3316 " |--Site A ------- proxies for B\n"
3317 " +--Site B ------- proxies for A\n"
3318 "Where A = http://bar.com/\n"
3319 " B = http://foo.com/",
3320 DepictFrameTree(popup_root));
3322 // Update the popup's second subframe's opener to root frame. This is
3323 // allowed because that subframe is in the same foo.com SiteInstance as the
3324 // root frame.
3325 bool success = false;
3326 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3327 root->current_frame_host(),
3328 "window.domAutomationController.send(!!window.open('','subframe2'));",
3329 &success));
3330 EXPECT_TRUE(success);
3332 // Check that the opener update propagated to the browser process and bar.com
3333 // process.
3334 EXPECT_EQ(root, popup_root->child_at(1)->opener());
3335 success = false;
3336 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3337 popup_root->child_at(0)->current_frame_host(),
3338 "window.domAutomationController.send("
3339 " parent.frames['subframe2'].opener && "
3340 " parent.frames['subframe2'].opener === parent.opener);",
3341 &success));
3342 EXPECT_TRUE(success);
3344 // Navigate the popup's first subframe to another site.
3345 GURL frame_url(
3346 embedded_test_server()->GetURL("baz.com", "/post_message.html"));
3347 NavigateFrameToURL(popup_root->child_at(0), frame_url);
3348 EXPECT_TRUE(
3349 WaitForRenderFrameReady(popup_root->child_at(0)->current_frame_host()));
3351 // Check that the second subframe's opener is still correct in the first
3352 // subframe's new process. Verify it both in JS and with a postMessage.
3353 success = false;
3354 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3355 popup_root->child_at(0)->current_frame_host(),
3356 "window.domAutomationController.send("
3357 " parent.frames['subframe2'].opener && "
3358 " parent.frames['subframe2'].opener === parent.opener);",
3359 &success));
3360 EXPECT_TRUE(success);
3362 base::string16 expected_title = base::ASCIIToUTF16("msg");
3363 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
3364 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3365 popup_root->child_at(0)->current_frame_host(),
3366 "window.domAutomationController.send("
3367 " postToOpenerOfSibling('subframe2', 'msg', '*'));",
3368 &success));
3369 EXPECT_TRUE(success);
3370 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
3373 } // namespace content