[refactor] More post-NSS WebCrypto cleanups (utility functions).
[chromium-blink-merge.git] / content / browser / site_per_process_browsertest.cc
blobd500ce60e40f4ba222745b220de50392867d9365
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) || defined(OS_LINUX)
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 // Test is flaky under Linux, see https://crbug.com/528189
463 #define MAYBE_SurfaceHitTestTest DISABLED_SurfaceHitTestTest
464 #else
465 #define MAYBE_SurfaceHitTestTest SurfaceHitTestTest
466 #endif
467 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_SurfaceHitTestTest) {
468 if (!UseSurfacesEnabled())
469 return;
471 GURL main_url(embedded_test_server()->GetURL(
472 "/frame_tree/page_with_positioned_frame.html"));
473 NavigateToURL(shell(), main_url);
475 // It is safe to obtain the root frame tree node here, as it doesn't change.
476 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
477 ->GetFrameTree()
478 ->root();
479 ASSERT_EQ(1U, root->child_count());
481 FrameTreeNode* child_node = root->child_at(0);
482 GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
483 EXPECT_EQ(site_url, child_node->current_url());
484 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
485 child_node->current_frame_host()->GetSiteInstance());
487 // Create listeners for mouse events.
488 RenderWidgetHostMouseEventMonitor main_frame_monitor(
489 root->current_frame_host()->GetRenderWidgetHost());
490 RenderWidgetHostMouseEventMonitor child_frame_monitor(
491 child_node->current_frame_host()->GetRenderWidgetHost());
493 RenderWidgetHostInputEventRouter* router =
494 static_cast<WebContentsImpl*>(shell()->web_contents())
495 ->GetInputEventRouter();
497 RenderWidgetHostViewBase* root_view = static_cast<RenderWidgetHostViewBase*>(
498 root->current_frame_host()->GetRenderWidgetHost()->GetView());
499 RenderWidgetHostViewBase* rwhv_child = static_cast<RenderWidgetHostViewBase*>(
500 child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
502 // We need to wait for a compositor frame from the child frame, at which
503 // point its surface will be created.
504 while (rwhv_child->RendererFrameNumber() <= 0) {
505 // TODO(lazyboy): Find a better way to avoid sleeping like this. See
506 // http://crbug.com/405282 for details.
507 base::RunLoop run_loop;
508 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
509 FROM_HERE, run_loop.QuitClosure(),
510 base::TimeDelta::FromMilliseconds(10));
511 run_loop.Run();
514 uint32_t cur_render_frame_number = root_view->RendererFrameNumber();
516 // Target input event to child frame.
517 blink::WebMouseEvent child_event;
518 child_event.type = blink::WebInputEvent::MouseDown;
519 child_event.button = blink::WebPointerProperties::ButtonLeft;
520 child_event.x = 75;
521 child_event.y = 75;
522 child_event.clickCount = 1;
523 router->RouteMouseEvent(root_view, &child_event);
525 if (!child_frame_monitor.EventWasReceived()) {
526 main_frame_monitor.ResetEventReceived();
527 // This is working around a big synchronization problem. It is very
528 // difficult to know if we have received a compositor frame from the
529 // main frame renderer *after* it received the child frame's surface
530 // ID. Hit testing won't work until this happens. So if the hit test
531 // fails then we wait for another frame to arrive and try again.
532 // TODO(kenrb): We need a better way to do all of this, possibly coming
533 // from http://crbug.com/405282.
534 while (root_view->RendererFrameNumber() <= cur_render_frame_number) {
535 base::RunLoop run_loop;
536 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
537 FROM_HERE, run_loop.QuitClosure(),
538 base::TimeDelta::FromMilliseconds(10));
539 run_loop.Run();
541 router->RouteMouseEvent(root_view, &child_event);
544 EXPECT_TRUE(child_frame_monitor.EventWasReceived());
545 EXPECT_FALSE(main_frame_monitor.EventWasReceived());
547 child_frame_monitor.ResetEventReceived();
548 main_frame_monitor.ResetEventReceived();
550 // Target input event to main frame.
551 blink::WebMouseEvent main_event;
552 main_event.type = blink::WebInputEvent::MouseDown;
553 main_event.button = blink::WebPointerProperties::ButtonLeft;
554 main_event.x = 1;
555 main_event.y = 1;
556 main_event.clickCount = 1;
557 // Ladies and gentlemen, THIS is the main_event!
558 router->RouteMouseEvent(root_view, &main_event);
560 EXPECT_FALSE(child_frame_monitor.EventWasReceived());
561 EXPECT_TRUE(main_frame_monitor.EventWasReceived());
564 // Tests OOPIF rendering by checking that the RWH of the iframe generates
565 // OnSwapCompositorFrame message.
566 #if defined(OS_ANDROID)
567 // http://crbug.com/471850
568 #define MAYBE_CompositorFrameSwapped DISABLED_CompositorFrameSwapped
569 #else
570 #define MAYBE_CompositorFrameSwapped CompositorFrameSwapped
571 #endif
572 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
573 MAYBE_CompositorFrameSwapped) {
574 GURL main_url(embedded_test_server()->GetURL(
575 "a.com", "/cross_site_iframe_factory.html?a(baz)"));
576 NavigateToURL(shell(), main_url);
578 // It is safe to obtain the root frame tree node here, as it doesn't change.
579 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
580 ->GetFrameTree()
581 ->root();
582 ASSERT_EQ(1U, root->child_count());
584 FrameTreeNode* child_node = root->child_at(0);
585 GURL site_url(embedded_test_server()->GetURL(
586 "baz.com", "/cross_site_iframe_factory.html?baz()"));
587 EXPECT_EQ(site_url, child_node->current_url());
588 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
589 child_node->current_frame_host()->GetSiteInstance());
590 RenderWidgetHostViewBase* rwhv_base = static_cast<RenderWidgetHostViewBase*>(
591 child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
593 // Wait for OnSwapCompositorFrame message.
594 while (rwhv_base->RendererFrameNumber() <= 0) {
595 // TODO(lazyboy): Find a better way to avoid sleeping like this. See
596 // http://crbug.com/405282 for details.
597 base::RunLoop run_loop;
598 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
599 FROM_HERE, run_loop.QuitClosure(),
600 base::TimeDelta::FromMilliseconds(10));
601 run_loop.Run();
605 // Ensure that OOPIFs are deleted after navigating to a new main frame.
606 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CleanupCrossSiteIframe) {
607 GURL main_url(embedded_test_server()->GetURL(
608 "a.com", "/cross_site_iframe_factory.html?a(a,a(a,a(a)))"));
609 NavigateToURL(shell(), main_url);
611 // It is safe to obtain the root frame tree node here, as it doesn't change.
612 FrameTreeNode* root =
613 static_cast<WebContentsImpl*>(shell()->web_contents())->
614 GetFrameTree()->root();
616 TestNavigationObserver observer(shell()->web_contents());
618 // Load a cross-site page into both iframes.
619 GURL foo_url = embedded_test_server()->GetURL("foo.com", "/title2.html");
620 NavigateFrameToURL(root->child_at(0), foo_url);
621 EXPECT_TRUE(observer.last_navigation_succeeded());
622 EXPECT_EQ(foo_url, observer.last_navigation_url());
623 NavigateFrameToURL(root->child_at(1), foo_url);
624 EXPECT_TRUE(observer.last_navigation_succeeded());
625 EXPECT_EQ(foo_url, observer.last_navigation_url());
627 // Ensure that we have created a new process for the subframes.
628 EXPECT_EQ(
629 " Site A ------------ proxies for B\n"
630 " |--Site B ------- proxies for A\n"
631 " +--Site B ------- proxies for A\n"
632 "Where A = http://a.com/\n"
633 " B = http://foo.com/",
634 DepictFrameTree(root));
636 int subframe_process_id = root->child_at(0)
637 ->current_frame_host()
638 ->GetSiteInstance()
639 ->GetProcess()
640 ->GetID();
641 int subframe_rvh_id = root->child_at(0)
642 ->current_frame_host()
643 ->render_view_host()
644 ->GetRoutingID();
645 EXPECT_TRUE(RenderViewHost::FromID(subframe_process_id, subframe_rvh_id));
647 // Use Javascript in the parent to remove one of the frames and ensure that
648 // the subframe goes away.
649 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
650 "document.body.removeChild("
651 "document.querySelectorAll('iframe')[0])"));
652 ASSERT_EQ(1U, root->child_count());
654 // Load a new same-site page in the top-level frame and ensure the other
655 // subframe goes away.
656 GURL new_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
657 NavigateToURL(shell(), new_url);
658 ASSERT_EQ(0U, root->child_count());
660 // Ensure the RVH for the subframe gets cleaned up when the frame goes away.
661 EXPECT_FALSE(RenderViewHost::FromID(subframe_process_id, subframe_rvh_id));
664 // Ensure that root frames cannot be detached.
665 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, RestrictFrameDetach) {
666 GURL main_url(embedded_test_server()->GetURL(
667 "a.com", "/cross_site_iframe_factory.html?a(a,a(a,a(a)))"));
668 NavigateToURL(shell(), main_url);
670 // It is safe to obtain the root frame tree node here, as it doesn't change.
671 FrameTreeNode* root =
672 static_cast<WebContentsImpl*>(shell()->web_contents())->
673 GetFrameTree()->root();
675 TestNavigationObserver observer(shell()->web_contents());
677 // Load cross-site pages into both iframes.
678 GURL foo_url = embedded_test_server()->GetURL("foo.com", "/title2.html");
679 NavigateFrameToURL(root->child_at(0), foo_url);
680 EXPECT_TRUE(observer.last_navigation_succeeded());
681 EXPECT_EQ(foo_url, observer.last_navigation_url());
682 GURL bar_url = embedded_test_server()->GetURL("bar.com", "/title2.html");
683 NavigateFrameToURL(root->child_at(1), bar_url);
684 EXPECT_TRUE(observer.last_navigation_succeeded());
685 EXPECT_EQ(bar_url, observer.last_navigation_url());
687 // Ensure that we have created new processes for the subframes.
688 ASSERT_EQ(2U, root->child_count());
689 FrameTreeNode* foo_child = root->child_at(0);
690 SiteInstance* foo_site_instance =
691 foo_child->current_frame_host()->GetSiteInstance();
692 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), foo_site_instance);
693 FrameTreeNode* bar_child = root->child_at(1);
694 SiteInstance* bar_site_instance =
695 bar_child->current_frame_host()->GetSiteInstance();
696 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), bar_site_instance);
698 EXPECT_EQ(
699 " Site A ------------ proxies for B C\n"
700 " |--Site B ------- proxies for A C\n"
701 " +--Site C ------- proxies for A B\n"
702 "Where A = http://a.com/\n"
703 " B = http://foo.com/\n"
704 " C = http://bar.com/",
705 DepictFrameTree(root));
707 // Simulate an attempt to detach the root frame from foo_site_instance. This
708 // should kill foo_site_instance's process.
709 RenderFrameProxyHost* foo_mainframe_rfph =
710 root->render_manager()->GetRenderFrameProxyHost(foo_site_instance);
711 content::RenderProcessHostWatcher foo_terminated(
712 foo_mainframe_rfph->GetProcess(),
713 content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
714 FrameHostMsg_Detach evil_msg2(foo_mainframe_rfph->GetRoutingID());
715 IPC::IpcSecurityTestUtil::PwnMessageReceived(
716 foo_mainframe_rfph->GetProcess()->GetChannel(), evil_msg2);
717 foo_terminated.Wait();
719 EXPECT_EQ(
720 " Site A ------------ proxies for B C\n"
721 " |--Site B ------- proxies for A C\n"
722 " +--Site C ------- proxies for A B\n"
723 "Where A = http://a.com/\n"
724 " B = http://foo.com/ (no process)\n"
725 " C = http://bar.com/",
726 DepictFrameTree(root));
729 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NavigateRemoteFrame) {
730 GURL main_url(embedded_test_server()->GetURL(
731 "a.com", "/cross_site_iframe_factory.html?a(a,a(a,a(a)))"));
732 NavigateToURL(shell(), main_url);
734 // It is safe to obtain the root frame tree node here, as it doesn't change.
735 FrameTreeNode* root =
736 static_cast<WebContentsImpl*>(shell()->web_contents())->
737 GetFrameTree()->root();
739 TestNavigationObserver observer(shell()->web_contents());
741 // Load same-site page into iframe.
742 FrameTreeNode* child = root->child_at(0);
743 GURL http_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
744 NavigateFrameToURL(child, http_url);
745 EXPECT_EQ(http_url, observer.last_navigation_url());
746 EXPECT_TRUE(observer.last_navigation_succeeded());
748 // Load cross-site page into iframe.
749 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
750 NavigateFrameToURL(root->child_at(0), url);
751 EXPECT_TRUE(observer.last_navigation_succeeded());
752 EXPECT_EQ(url, observer.last_navigation_url());
754 // Ensure that we have created a new process for the subframe.
755 EXPECT_EQ(
756 " Site A ------------ proxies for B\n"
757 " |--Site B ------- proxies for A\n"
758 " +--Site A ------- proxies for B\n"
759 " |--Site A -- proxies for B\n"
760 " +--Site A -- proxies for B\n"
761 " +--Site A -- proxies for B\n"
762 "Where A = http://a.com/\n"
763 " B = http://foo.com/",
764 DepictFrameTree(root));
765 SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
766 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
768 // Emulate the main frame changing the src of the iframe such that it
769 // navigates cross-site.
770 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
771 NavigateIframeToURL(shell()->web_contents(), "child-0", url);
772 EXPECT_TRUE(observer.last_navigation_succeeded());
773 EXPECT_EQ(url, observer.last_navigation_url());
775 // Check again that a new process is created and is different from the
776 // top level one and the previous one.
777 EXPECT_EQ(
778 " Site A ------------ proxies for C\n"
779 " |--Site C ------- proxies for A\n"
780 " +--Site A ------- proxies for C\n"
781 " |--Site A -- proxies for C\n"
782 " +--Site A -- proxies for C\n"
783 " +--Site A -- proxies for C\n"
784 "Where A = http://a.com/\n"
785 " C = http://bar.com/",
786 DepictFrameTree(root));
788 // Navigate back to the parent's origin and ensure we return to the
789 // parent's process.
790 NavigateFrameToURL(child, http_url);
791 EXPECT_EQ(http_url, observer.last_navigation_url());
792 EXPECT_TRUE(observer.last_navigation_succeeded());
793 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
794 child->current_frame_host()->GetSiteInstance());
797 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
798 NavigateRemoteFrameToBlankAndDataURLs) {
799 GURL main_url(embedded_test_server()->GetURL(
800 "a.com", "/cross_site_iframe_factory.html?a(a,a(a))"));
801 NavigateToURL(shell(), main_url);
803 // It is safe to obtain the root frame tree node here, as it doesn't change.
804 FrameTreeNode* root =
805 static_cast<WebContentsImpl*>(shell()->web_contents())->
806 GetFrameTree()->root();
808 TestNavigationObserver observer(shell()->web_contents());
810 // Load same-site page into iframe.
811 FrameTreeNode* child = root->child_at(0);
812 GURL http_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
813 NavigateFrameToURL(child, http_url);
814 EXPECT_EQ(http_url, observer.last_navigation_url());
815 EXPECT_TRUE(observer.last_navigation_succeeded());
816 EXPECT_EQ(
817 " Site A\n"
818 " |--Site A\n"
819 " +--Site A\n"
820 " +--Site A\n"
821 "Where A = http://a.com/",
822 DepictFrameTree(root));
824 // Load cross-site page into iframe.
825 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
826 NavigateFrameToURL(root->child_at(0), url);
827 EXPECT_TRUE(observer.last_navigation_succeeded());
828 EXPECT_EQ(url, observer.last_navigation_url());
829 EXPECT_EQ(
830 " Site A ------------ proxies for B\n"
831 " |--Site B ------- proxies for A\n"
832 " +--Site A ------- proxies for B\n"
833 " +--Site A -- proxies for B\n"
834 "Where A = http://a.com/\n"
835 " B = http://foo.com/",
836 DepictFrameTree(root));
838 // Navigate iframe to a data URL. The navigation happens from a script in the
839 // parent frame, so the data URL should be committed in the same SiteInstance
840 // as the parent frame.
841 GURL data_url("data:text/html,dataurl");
842 NavigateIframeToURL(shell()->web_contents(), "child-0", data_url);
843 EXPECT_TRUE(observer.last_navigation_succeeded());
844 EXPECT_EQ(data_url, observer.last_navigation_url());
846 // Ensure that we have navigated using the top level process.
847 EXPECT_EQ(
848 " Site A\n"
849 " |--Site A\n"
850 " +--Site A\n"
851 " +--Site A\n"
852 "Where A = http://a.com/",
853 DepictFrameTree(root));
855 // Load cross-site page into iframe.
856 url = embedded_test_server()->GetURL("bar.com", "/title2.html");
857 NavigateFrameToURL(root->child_at(0), url);
858 EXPECT_TRUE(observer.last_navigation_succeeded());
859 EXPECT_EQ(url, observer.last_navigation_url());
860 EXPECT_EQ(
861 " Site A ------------ proxies for C\n"
862 " |--Site C ------- proxies for A\n"
863 " +--Site A ------- proxies for C\n"
864 " +--Site A -- proxies for C\n"
865 "Where A = http://a.com/\n"
866 " C = http://bar.com/",
867 DepictFrameTree(root));
869 // Navigate iframe to about:blank. The navigation happens from a script in the
870 // parent frame, so it should be committed in the same SiteInstance as the
871 // parent frame.
872 GURL about_blank_url("about:blank");
873 NavigateIframeToURL(shell()->web_contents(), "child-0", about_blank_url);
874 EXPECT_TRUE(observer.last_navigation_succeeded());
875 EXPECT_EQ(about_blank_url, observer.last_navigation_url());
877 // Ensure that we have navigated using the top level process.
878 EXPECT_EQ(
879 " Site A\n"
880 " |--Site A\n"
881 " +--Site A\n"
882 " +--Site A\n"
883 "Where A = http://a.com/",
884 DepictFrameTree(root));
887 // This test checks that killing a renderer process of a remote frame
888 // and then navigating some other frame to the same SiteInstance of the killed
889 // process works properly.
890 // This can be illustrated as follows,
891 // where 1/2/3 are FrameTreeNode-s and A/B are processes and B* is the killed
892 // B process:
894 // 1 A A A
895 // / \ -> / \ -> Kill B -> / \ -> Navigate 3 to B -> / \ .
896 // 2 3 B A B* A B* B
898 // Initially, node1.proxy_hosts_ = {B}
899 // After we kill B, we make sure B stays in node1.proxy_hosts_, then we navigate
900 // 3 to B and we expect that to complete normally.
901 // See http://crbug.com/432107.
903 // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
904 // site B and stays in not rendered state.
905 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
906 NavigateRemoteFrameToKilledProcess) {
907 GURL main_url(embedded_test_server()->GetURL(
908 "foo.com", "/cross_site_iframe_factory.html?foo.com(bar.com, foo.com)"));
909 NavigateToURL(shell(), main_url);
911 // It is safe to obtain the root frame tree node here, as it doesn't change.
912 FrameTreeNode* root =
913 static_cast<WebContentsImpl*>(shell()->web_contents())->
914 GetFrameTree()->root();
916 TestNavigationObserver observer(shell()->web_contents());
917 ASSERT_EQ(2U, root->child_count());
919 // Make sure node2 points to the correct cross-site page.
920 GURL site_b_url = embedded_test_server()->GetURL(
921 "bar.com", "/cross_site_iframe_factory.html?bar.com()");
922 FrameTreeNode* node2 = root->child_at(0);
923 EXPECT_EQ(site_b_url, node2->current_url());
925 // Kill that cross-site renderer.
926 RenderProcessHost* child_process =
927 node2->current_frame_host()->GetProcess();
928 RenderProcessHostWatcher crash_observer(
929 child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
930 child_process->Shutdown(0, false);
931 crash_observer.Wait();
933 // Now navigate the second iframe (node3) to the same site as the node2.
934 FrameTreeNode* node3 = root->child_at(1);
935 NavigateFrameToURL(node3, site_b_url);
936 EXPECT_TRUE(observer.last_navigation_succeeded());
937 EXPECT_EQ(site_b_url, observer.last_navigation_url());
940 // This test is similar to
941 // SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcess with
942 // addition that node2 also has a cross-origin frame to site C.
944 // 1 A A A
945 // / \ / \ / \ / \ .
946 // 2 3 -> B A -> Kill B -> B* A -> Navigate 3 -> B* B
947 // / /
948 // 4 C
950 // Initially, node1.proxy_hosts_ = {B, C}
951 // After we kill B, we make sure B stays in node1.proxy_hosts_, but
952 // C gets cleared from node1.proxy_hosts_.
954 // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
955 // site B and stays in not rendered state.
956 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
957 NavigateRemoteFrameToKilledProcessWithSubtree) {
958 GURL main_url(embedded_test_server()->GetURL(
959 "a.com", "/cross_site_iframe_factory.html?a(bar(baz), a)"));
960 NavigateToURL(shell(), main_url);
962 // It is safe to obtain the root frame tree node here, as it doesn't change.
963 FrameTreeNode* root =
964 static_cast<WebContentsImpl*>(shell()->web_contents())->
965 GetFrameTree()->root();
966 TestNavigationObserver observer(shell()->web_contents());
968 ASSERT_EQ(2U, root->child_count());
970 GURL site_b_url(embedded_test_server()->GetURL(
971 "bar.com", "/cross_site_iframe_factory.html?bar(baz())"));
972 // We can't use a TestNavigationObserver to verify the URL here,
973 // since the frame has children that may have clobbered it in the observer.
974 EXPECT_EQ(site_b_url, root->child_at(0)->current_url());
976 // Ensure that a new process is created for node2.
977 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
978 root->child_at(0)->current_frame_host()->GetSiteInstance());
979 // Ensure that a new process is *not* created for node3.
980 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
981 root->child_at(1)->current_frame_host()->GetSiteInstance());
983 ASSERT_EQ(1U, root->child_at(0)->child_count());
985 // Make sure node4 points to the correct cross-site page.
986 FrameTreeNode* node4 = root->child_at(0)->child_at(0);
987 GURL site_c_url(embedded_test_server()->GetURL(
988 "baz.com", "/cross_site_iframe_factory.html?baz()"));
989 EXPECT_EQ(site_c_url, node4->current_url());
991 // |site_instance_c| is expected to go away once we kill |child_process_b|
992 // below, so create a local scope so we can extend the lifetime of
993 // |site_instance_c| with a refptr.
995 // Initially each frame has proxies for the other sites.
996 EXPECT_EQ(
997 " Site A ------------ proxies for B C\n"
998 " |--Site B ------- proxies for A C\n"
999 " | +--Site C -- proxies for A B\n"
1000 " +--Site A ------- proxies for B C\n"
1001 "Where A = http://a.com/\n"
1002 " B = http://bar.com/\n"
1003 " C = http://baz.com/",
1004 DepictFrameTree(root));
1006 // Kill the render process for Site B.
1007 RenderProcessHost* child_process_b =
1008 root->child_at(0)->current_frame_host()->GetProcess();
1009 RenderProcessHostWatcher crash_observer(
1010 child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1011 child_process_b->Shutdown(0, false);
1012 crash_observer.Wait();
1014 // The Site C frame (a child of the crashed Site B frame) should go away,
1015 // and there should be no remaining proxies for site C anywhere.
1016 EXPECT_EQ(
1017 " Site A ------------ proxies for B\n"
1018 " |--Site B ------- proxies for A\n"
1019 " +--Site A ------- proxies for B\n"
1020 "Where A = http://a.com/\n"
1021 " B = http://bar.com/ (no process)",
1022 DepictFrameTree(root));
1025 // Now navigate the second iframe (node3) to Site B also.
1026 FrameTreeNode* node3 = root->child_at(1);
1027 GURL url = embedded_test_server()->GetURL("bar.com", "/title1.html");
1028 NavigateFrameToURL(node3, url);
1029 EXPECT_TRUE(observer.last_navigation_succeeded());
1030 EXPECT_EQ(url, observer.last_navigation_url());
1032 EXPECT_EQ(
1033 " Site A ------------ proxies for B\n"
1034 " |--Site B ------- proxies for A\n"
1035 " +--Site B ------- proxies for A\n"
1036 "Where A = http://a.com/\n"
1037 " B = http://bar.com/",
1038 DepictFrameTree(root));
1041 // Verify that killing a cross-site frame's process B and then navigating a
1042 // frame to B correctly recreates all proxies in B.
1044 // 1 A A A
1045 // / | \ / | \ / | \ / | \ .
1046 // 2 3 4 -> B A A -> Kill B -> B* A A -> B* B A
1048 // After the last step, the test sends a postMessage from node 3 to node 4,
1049 // verifying that a proxy for node 4 has been recreated in process B. This
1050 // verifies the fix for https://crbug.com/478892.
1051 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1052 NavigatingToKilledProcessRestoresAllProxies) {
1053 // Navigate to a page with three frames: one cross-site and two same-site.
1054 GURL main_url(embedded_test_server()->GetURL(
1055 "a.com", "/frame_tree/page_with_three_frames.html"));
1056 NavigateToURL(shell(), main_url);
1058 // It is safe to obtain the root frame tree node here, as it doesn't change.
1059 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1060 ->GetFrameTree()
1061 ->root();
1062 TestNavigationObserver observer(shell()->web_contents());
1064 EXPECT_EQ(
1065 " Site A ------------ proxies for B\n"
1066 " |--Site B ------- proxies for A\n"
1067 " |--Site A ------- proxies for B\n"
1068 " +--Site A ------- proxies for B\n"
1069 "Where A = http://a.com/\n"
1070 " B = http://b.com/",
1071 DepictFrameTree(root));
1073 // Kill the first subframe's b.com renderer.
1074 RenderProcessHost* child_process =
1075 root->child_at(0)->current_frame_host()->GetProcess();
1076 RenderProcessHostWatcher crash_observer(
1077 child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1078 child_process->Shutdown(0, false);
1079 crash_observer.Wait();
1081 // Navigate the second subframe to b.com to recreate the b.com process.
1082 GURL b_url = embedded_test_server()->GetURL("b.com", "/post_message.html");
1083 NavigateFrameToURL(root->child_at(1), b_url);
1084 // TODO(alexmos): This can be removed once TestFrameNavigationObserver is
1085 // fixed to use DidFinishLoad.
1086 EXPECT_TRUE(
1087 WaitForRenderFrameReady(root->child_at(1)->current_frame_host()));
1088 EXPECT_TRUE(observer.last_navigation_succeeded());
1089 EXPECT_EQ(b_url, observer.last_navigation_url());
1090 EXPECT_TRUE(root->child_at(1)->current_frame_host()->IsRenderFrameLive());
1092 EXPECT_EQ(
1093 " Site A ------------ proxies for B\n"
1094 " |--Site B ------- proxies for A\n"
1095 " |--Site B ------- proxies for A\n"
1096 " +--Site A ------- proxies for B\n"
1097 "Where A = http://a.com/\n"
1098 " B = http://b.com/",
1099 DepictFrameTree(root));
1101 // Check that third subframe's proxy is available in the b.com process by
1102 // sending it a postMessage from second subframe, and waiting for a reply.
1103 PostMessageAndWaitForReply(root->child_at(1),
1104 "postToSibling('subframe-msg','frame3')",
1105 "\"done-frame2\"");
1108 // Verify that proxy creation doesn't recreate a crashed process if no frame
1109 // will be created in it.
1111 // 1 A A A
1112 // / | \ / | \ / | \ / | \ .
1113 // 2 3 4 -> B A A -> Kill B -> B* A A -> B* A A
1114 // \ .
1115 // A
1117 // The test kills process B (node 2), creates a child frame of node 4 in
1118 // process A, and then checks that process B isn't resurrected to create a
1119 // proxy for the new child frame. See https://crbug.com/476846.
1120 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1121 CreateChildFrameAfterKillingProcess) {
1122 // Navigate to a page with three frames: one cross-site and two same-site.
1123 GURL main_url(embedded_test_server()->GetURL(
1124 "a.com", "/frame_tree/page_with_three_frames.html"));
1125 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1127 // It is safe to obtain the root frame tree node here, as it doesn't change.
1128 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1129 ->GetFrameTree()
1130 ->root();
1132 EXPECT_EQ(
1133 " Site A ------------ proxies for B\n"
1134 " |--Site B ------- proxies for A\n"
1135 " |--Site A ------- proxies for B\n"
1136 " +--Site A ------- proxies for B\n"
1137 "Where A = http://a.com/\n"
1138 " B = http://b.com/",
1139 DepictFrameTree(root));
1140 SiteInstance* b_site_instance =
1141 root->child_at(0)->current_frame_host()->GetSiteInstance();
1143 // Kill the first subframe's renderer (B).
1144 RenderProcessHost* child_process =
1145 root->child_at(0)->current_frame_host()->GetProcess();
1146 RenderProcessHostWatcher crash_observer(
1147 child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1148 child_process->Shutdown(0, false);
1149 crash_observer.Wait();
1151 // Add a new child frame to the third subframe.
1152 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 1);
1153 EXPECT_TRUE(ExecuteScript(
1154 root->child_at(2)->current_frame_host(),
1155 "document.body.appendChild(document.createElement('iframe'));"));
1156 frame_observer.Wait();
1158 // The new frame should have a RenderFrameProxyHost for B, but it should not
1159 // be alive, and B should still not have a process (verified by last line of
1160 // expected DepictFrameTree output).
1161 EXPECT_EQ(
1162 " Site A ------------ proxies for B\n"
1163 " |--Site B ------- proxies for A\n"
1164 " |--Site A ------- proxies for B\n"
1165 " +--Site A ------- proxies for B\n"
1166 " +--Site A -- proxies for B\n"
1167 "Where A = http://a.com/\n"
1168 " B = http://b.com/ (no process)",
1169 DepictFrameTree(root));
1170 FrameTreeNode* grandchild = root->child_at(2)->child_at(0);
1171 RenderFrameProxyHost* grandchild_rfph =
1172 grandchild->render_manager()->GetRenderFrameProxyHost(b_site_instance);
1173 EXPECT_FALSE(grandchild_rfph->is_render_frame_proxy_live());
1175 // Navigate the second subframe to b.com to recreate process B.
1176 TestNavigationObserver observer(shell()->web_contents());
1177 GURL b_url = embedded_test_server()->GetURL("b.com", "/title1.html");
1178 NavigateFrameToURL(root->child_at(1), b_url);
1179 EXPECT_TRUE(observer.last_navigation_succeeded());
1180 EXPECT_EQ(b_url, observer.last_navigation_url());
1182 // Ensure that the grandchild RenderFrameProxy in B was created when process
1183 // B was restored.
1184 EXPECT_TRUE(grandchild_rfph->is_render_frame_proxy_live());
1187 // Verify that creating a child frame after killing and reloading an opener
1188 // process doesn't crash. See https://crbug.com/501152.
1189 // 1. Navigate to site A.
1190 // 2. Open a popup with window.open and navigate it cross-process to site B.
1191 // 3. Kill process A for the original tab.
1192 // 4. Reload the original tab to resurrect process A.
1193 // 5. Add a child frame to the top-level frame in the popup tab B.
1194 // In step 5, we try to create proxies for the child frame in all SiteInstances
1195 // for which its parent has proxies. This includes A. However, even though
1196 // process A is live (step 4), the parent proxy in A is not live (which was
1197 // incorrectly assumed previously). This is because step 4 does not resurrect
1198 // proxies for popups opened before the crash.
1199 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1200 CreateChildFrameAfterKillingOpener) {
1201 GURL main_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
1202 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1204 // It is safe to obtain the root frame tree node here, as it doesn't change.
1205 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1206 ->GetFrameTree()
1207 ->root();
1208 SiteInstance* site_instance_a = root->current_frame_host()->GetSiteInstance();
1210 // Open a popup and navigate it cross-process to b.com.
1211 ShellAddedObserver new_shell_observer;
1212 EXPECT_TRUE(ExecuteScript(root->current_frame_host(),
1213 "popup = window.open('about:blank');"));
1214 Shell* popup = new_shell_observer.GetShell();
1215 GURL popup_url(embedded_test_server()->GetURL("b.com", "/title2.html"));
1216 EXPECT_TRUE(NavigateToURL(popup, popup_url));
1218 // Verify that each top-level frame has proxies in the other's SiteInstance.
1219 FrameTreeNode* popup_root =
1220 static_cast<WebContentsImpl*>(popup->web_contents())
1221 ->GetFrameTree()
1222 ->root();
1223 EXPECT_EQ(
1224 " Site A ------------ proxies for B\n"
1225 "Where A = http://a.com/\n"
1226 " B = http://b.com/",
1227 DepictFrameTree(root));
1228 EXPECT_EQ(
1229 " Site B ------------ proxies for A\n"
1230 "Where A = http://a.com/\n"
1231 " B = http://b.com/",
1232 DepictFrameTree(popup_root));
1234 // Kill the first window's renderer (a.com).
1235 RenderProcessHost* child_process = root->current_frame_host()->GetProcess();
1236 RenderProcessHostWatcher crash_observer(
1237 child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1238 child_process->Shutdown(0, false);
1239 crash_observer.Wait();
1240 EXPECT_FALSE(root->current_frame_host()->IsRenderFrameLive());
1242 // The proxy for the popup in a.com should've died.
1243 RenderFrameProxyHost* rfph =
1244 popup_root->render_manager()->GetRenderFrameProxyHost(site_instance_a);
1245 EXPECT_FALSE(rfph->is_render_frame_proxy_live());
1247 // Recreate the a.com renderer.
1248 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1249 EXPECT_TRUE(root->current_frame_host()->IsRenderFrameLive());
1251 // The popup's proxy in a.com should still not be live. Re-navigating the
1252 // main window to a.com doesn't reinitialize a.com proxies for popups
1253 // previously opened from the main window.
1254 EXPECT_FALSE(rfph->is_render_frame_proxy_live());
1256 // Add a new child frame on the popup.
1257 RenderFrameHostCreatedObserver frame_observer(popup->web_contents(), 1);
1258 EXPECT_TRUE(ExecuteScript(
1259 popup->web_contents(),
1260 "document.body.appendChild(document.createElement('iframe'));"));
1261 frame_observer.Wait();
1263 // Both the child frame's and its parent's proxies should still not be live.
1264 // The main page can't reach them since it lost reference to the popup after
1265 // it crashed, so there is no need to create them.
1266 EXPECT_FALSE(rfph->is_render_frame_proxy_live());
1267 RenderFrameProxyHost* child_rfph =
1268 popup_root->child_at(0)->render_manager()->GetRenderFrameProxyHost(
1269 site_instance_a);
1270 EXPECT_TRUE(child_rfph);
1271 EXPECT_FALSE(child_rfph->is_render_frame_proxy_live());
1274 // In A-embed-B-embed-C scenario, verify that killing process B clears proxies
1275 // of C from the tree.
1277 // 1 A A
1278 // / \ / \ / \ .
1279 // 2 3 -> B A -> Kill B -> B* A
1280 // / /
1281 // 4 C
1283 // node1 is the root.
1284 // Initially, both node1.proxy_hosts_ and node3.proxy_hosts_ contain C.
1285 // After we kill B, make sure proxies for C are cleared.
1286 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1287 KillingRendererClearsDescendantProxies) {
1288 GURL main_url(embedded_test_server()->GetURL(
1289 "a.com", "/frame_tree/page_with_two_frames_nested.html"));
1290 NavigateToURL(shell(), main_url);
1292 // It is safe to obtain the root frame tree node here, as it doesn't change.
1293 FrameTreeNode* root =
1294 static_cast<WebContentsImpl*>(shell()->web_contents())->
1295 GetFrameTree()->root();
1296 ASSERT_EQ(2U, root->child_count());
1298 GURL site_b_url(
1299 embedded_test_server()->GetURL(
1300 "bar.com", "/frame_tree/page_with_one_frame.html"));
1301 // We can't use a TestNavigationObserver to verify the URL here,
1302 // since the frame has children that may have clobbered it in the observer.
1303 EXPECT_EQ(site_b_url, root->child_at(0)->current_url());
1305 // Ensure that a new process is created for node2.
1306 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1307 root->child_at(0)->current_frame_host()->GetSiteInstance());
1308 // Ensure that a new process is *not* created for node3.
1309 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
1310 root->child_at(1)->current_frame_host()->GetSiteInstance());
1312 ASSERT_EQ(1U, root->child_at(0)->child_count());
1314 // Make sure node4 points to the correct cross-site-page.
1315 FrameTreeNode* node4 = root->child_at(0)->child_at(0);
1316 GURL site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
1317 EXPECT_EQ(site_c_url, node4->current_url());
1319 // |site_instance_c|'s frames and proxies are expected to go away once we kill
1320 // |child_process_b| below.
1321 scoped_refptr<SiteInstanceImpl> site_instance_c =
1322 node4->current_frame_host()->GetSiteInstance();
1324 // Initially proxies for both B and C will be present in the root.
1325 EXPECT_EQ(
1326 " Site A ------------ proxies for B C\n"
1327 " |--Site B ------- proxies for A C\n"
1328 " | +--Site C -- proxies for A B\n"
1329 " +--Site A ------- proxies for B C\n"
1330 "Where A = http://a.com/\n"
1331 " B = http://bar.com/\n"
1332 " C = http://baz.com/",
1333 DepictFrameTree(root));
1335 EXPECT_GT(site_instance_c->active_frame_count(), 0U);
1337 // Kill process B.
1338 RenderProcessHost* child_process_b =
1339 root->child_at(0)->current_frame_host()->GetProcess();
1340 RenderProcessHostWatcher crash_observer(
1341 child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1342 child_process_b->Shutdown(0, false);
1343 crash_observer.Wait();
1345 // Make sure proxy C has gone from root.
1346 // Make sure proxy C has gone from node3 as well.
1347 // Make sure proxy B stays around in root and node3.
1348 EXPECT_EQ(
1349 " Site A ------------ proxies for B\n"
1350 " |--Site B ------- proxies for A\n"
1351 " +--Site A ------- proxies for B\n"
1352 "Where A = http://a.com/\n"
1353 " B = http://bar.com/ (no process)",
1354 DepictFrameTree(root));
1356 EXPECT_EQ(0U, site_instance_c->active_frame_count());
1359 // Crash a subframe and ensures its children are cleared from the FrameTree.
1360 // See http://crbug.com/338508.
1361 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrashSubframe) {
1362 GURL main_url(embedded_test_server()->GetURL(
1363 "a.com", "/cross_site_iframe_factory.html?a(b)"));
1364 NavigateToURL(shell(), main_url);
1366 // Check the subframe process.
1367 FrameTreeNode* root =
1368 static_cast<WebContentsImpl*>(shell()->web_contents())->
1369 GetFrameTree()->root();
1370 EXPECT_EQ(
1371 " Site A ------------ proxies for B\n"
1372 " +--Site B ------- proxies for A\n"
1373 "Where A = http://a.com/\n"
1374 " B = http://b.com/",
1375 DepictFrameTree(root));
1376 FrameTreeNode* child = root->child_at(0);
1377 EXPECT_TRUE(
1378 child->current_frame_host()->render_view_host()->IsRenderViewLive());
1379 EXPECT_TRUE(child->current_frame_host()->IsRenderFrameLive());
1381 // Crash the subframe process.
1382 RenderProcessHost* root_process = root->current_frame_host()->GetProcess();
1383 RenderProcessHost* child_process = child->current_frame_host()->GetProcess();
1385 RenderProcessHostWatcher crash_observer(
1386 child_process,
1387 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1388 child_process->Shutdown(0, false);
1389 crash_observer.Wait();
1392 // Ensure that the child frame still exists but has been cleared.
1393 EXPECT_EQ(
1394 " Site A ------------ proxies for B\n"
1395 " +--Site B ------- proxies for A\n"
1396 "Where A = http://a.com/\n"
1397 " B = http://b.com/ (no process)",
1398 DepictFrameTree(root));
1399 EXPECT_EQ(1U, root->child_count());
1400 EXPECT_EQ(main_url, root->current_url());
1401 EXPECT_EQ(GURL(), child->current_url());
1403 EXPECT_FALSE(
1404 child->current_frame_host()->render_view_host()->IsRenderViewLive());
1405 EXPECT_FALSE(child->current_frame_host()->IsRenderFrameLive());
1406 EXPECT_FALSE(child->current_frame_host()->render_frame_created_);
1408 // Now crash the top-level page to clear the child frame.
1410 RenderProcessHostWatcher crash_observer(
1411 root_process,
1412 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
1413 root_process->Shutdown(0, false);
1414 crash_observer.Wait();
1416 EXPECT_EQ(0U, root->child_count());
1417 EXPECT_EQ(GURL(), root->current_url());
1420 // When a new subframe is added, related SiteInstances that can reach the
1421 // subframe should create proxies for it (https://crbug.com/423587). This test
1422 // checks that if A embeds B and later adds a new subframe A2, A2 gets a proxy
1423 // in B's process.
1424 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CreateProxiesForNewFrames) {
1425 GURL main_url(embedded_test_server()->GetURL(
1426 "b.com", "/frame_tree/page_with_one_frame.html"));
1427 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1429 // It is safe to obtain the root frame tree node here, as it doesn't change.
1430 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1431 ->GetFrameTree()
1432 ->root();
1433 ASSERT_EQ(1U, root->child_count());
1435 // Make sure the frame starts out at the correct cross-site URL.
1436 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"),
1437 root->child_at(0)->current_url());
1439 EXPECT_EQ(
1440 " Site A ------------ proxies for B\n"
1441 " +--Site B ------- proxies for A\n"
1442 "Where A = http://b.com/\n"
1443 " B = http://baz.com/",
1444 DepictFrameTree(root));
1446 // Add a new child frame to the top-level frame.
1447 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 1);
1448 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1449 "window.domAutomationController.send("
1450 " addFrame('data:text/html,foo'));"));
1451 frame_observer.Wait();
1453 // The new frame should have a proxy in Site B, for use by the old frame.
1454 EXPECT_EQ(
1455 " Site A ------------ proxies for B\n"
1456 " |--Site B ------- proxies for A\n"
1457 " +--Site A ------- proxies for B\n"
1458 "Where A = http://b.com/\n"
1459 " B = http://baz.com/",
1460 DepictFrameTree(root));
1463 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
1464 // security checks are back in place.
1465 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
1466 // on Android (http://crbug.com/187570).
1467 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1468 DISABLED_CrossSiteIframeRedirectOnce) {
1469 ASSERT_TRUE(test_server()->Start());
1470 net::SpawnedTestServer https_server(
1471 net::SpawnedTestServer::TYPE_HTTPS,
1472 net::SpawnedTestServer::kLocalhost,
1473 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
1474 ASSERT_TRUE(https_server.Start());
1476 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
1477 GURL http_url(test_server()->GetURL("files/title1.html"));
1478 GURL https_url(https_server.GetURL("files/title1.html"));
1480 NavigateToURL(shell(), main_url);
1482 TestNavigationObserver observer(shell()->web_contents());
1484 // Load cross-site client-redirect page into Iframe.
1485 // Should be blocked.
1486 GURL client_redirect_https_url(https_server.GetURL(
1487 "client-redirect?files/title1.html"));
1488 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1489 client_redirect_https_url));
1490 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
1491 EXPECT_EQ(observer.last_navigation_url(), client_redirect_https_url);
1492 EXPECT_FALSE(observer.last_navigation_succeeded());
1496 // Load cross-site server-redirect page into Iframe,
1497 // which redirects to same-site page.
1498 GURL server_redirect_http_url(https_server.GetURL(
1499 "server-redirect?" + http_url.spec()));
1500 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1501 server_redirect_http_url));
1502 EXPECT_EQ(observer.last_navigation_url(), http_url);
1503 EXPECT_TRUE(observer.last_navigation_succeeded());
1507 // Load cross-site server-redirect page into Iframe,
1508 // which redirects to cross-site page.
1509 GURL server_redirect_http_url(https_server.GetURL(
1510 "server-redirect?files/title1.html"));
1511 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1512 server_redirect_http_url));
1513 // DidFailProvisionalLoad when navigating to https_url.
1514 EXPECT_EQ(observer.last_navigation_url(), https_url);
1515 EXPECT_FALSE(observer.last_navigation_succeeded());
1519 // Load same-site server-redirect page into Iframe,
1520 // which redirects to cross-site page.
1521 GURL server_redirect_http_url(test_server()->GetURL(
1522 "server-redirect?" + https_url.spec()));
1523 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1524 server_redirect_http_url));
1526 EXPECT_EQ(observer.last_navigation_url(), https_url);
1527 EXPECT_FALSE(observer.last_navigation_succeeded());
1531 // Load same-site client-redirect page into Iframe,
1532 // which redirects to cross-site page.
1533 GURL client_redirect_http_url(test_server()->GetURL(
1534 "client-redirect?" + https_url.spec()));
1536 RedirectNotificationObserver load_observer2(
1537 NOTIFICATION_LOAD_STOP,
1538 Source<NavigationController>(
1539 &shell()->web_contents()->GetController()));
1541 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1542 client_redirect_http_url));
1544 // Same-site Client-Redirect Page should be loaded successfully.
1545 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
1546 EXPECT_TRUE(observer.last_navigation_succeeded());
1548 // Redirecting to Cross-site Page should be blocked.
1549 load_observer2.Wait();
1550 EXPECT_EQ(observer.last_navigation_url(), https_url);
1551 EXPECT_FALSE(observer.last_navigation_succeeded());
1555 // Load same-site server-redirect page into Iframe,
1556 // which redirects to same-site page.
1557 GURL server_redirect_http_url(test_server()->GetURL(
1558 "server-redirect?files/title1.html"));
1559 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1560 server_redirect_http_url));
1561 EXPECT_EQ(observer.last_navigation_url(), http_url);
1562 EXPECT_TRUE(observer.last_navigation_succeeded());
1566 // Load same-site client-redirect page into Iframe,
1567 // which redirects to same-site page.
1568 GURL client_redirect_http_url(test_server()->GetURL(
1569 "client-redirect?" + http_url.spec()));
1570 RedirectNotificationObserver load_observer2(
1571 NOTIFICATION_LOAD_STOP,
1572 Source<NavigationController>(
1573 &shell()->web_contents()->GetController()));
1575 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1576 client_redirect_http_url));
1578 // Same-site Client-Redirect Page should be loaded successfully.
1579 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
1580 EXPECT_TRUE(observer.last_navigation_succeeded());
1582 // Redirecting to Same-site Page should be loaded successfully.
1583 load_observer2.Wait();
1584 EXPECT_EQ(observer.last_navigation_url(), http_url);
1585 EXPECT_TRUE(observer.last_navigation_succeeded());
1589 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
1590 // security checks are back in place.
1591 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
1592 // on Android (http://crbug.com/187570).
1593 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1594 DISABLED_CrossSiteIframeRedirectTwice) {
1595 ASSERT_TRUE(test_server()->Start());
1596 net::SpawnedTestServer https_server(
1597 net::SpawnedTestServer::TYPE_HTTPS,
1598 net::SpawnedTestServer::kLocalhost,
1599 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
1600 ASSERT_TRUE(https_server.Start());
1602 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
1603 GURL http_url(test_server()->GetURL("files/title1.html"));
1604 GURL https_url(https_server.GetURL("files/title1.html"));
1606 NavigateToURL(shell(), main_url);
1608 TestNavigationObserver observer(shell()->web_contents());
1610 // Load client-redirect page pointing to a cross-site client-redirect page,
1611 // which eventually redirects back to same-site page.
1612 GURL client_redirect_https_url(https_server.GetURL(
1613 "client-redirect?" + http_url.spec()));
1614 GURL client_redirect_http_url(test_server()->GetURL(
1615 "client-redirect?" + client_redirect_https_url.spec()));
1617 // We should wait until second client redirect get cancelled.
1618 RedirectNotificationObserver load_observer2(
1619 NOTIFICATION_LOAD_STOP,
1620 Source<NavigationController>(
1621 &shell()->web_contents()->GetController()));
1623 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1624 client_redirect_http_url));
1626 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
1627 load_observer2.Wait();
1628 EXPECT_EQ(observer.last_navigation_url(), client_redirect_https_url);
1629 EXPECT_FALSE(observer.last_navigation_succeeded());
1633 // Load server-redirect page pointing to a cross-site server-redirect page,
1634 // which eventually redirect back to same-site page.
1635 GURL server_redirect_https_url(https_server.GetURL(
1636 "server-redirect?" + http_url.spec()));
1637 GURL server_redirect_http_url(test_server()->GetURL(
1638 "server-redirect?" + server_redirect_https_url.spec()));
1639 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1640 server_redirect_http_url));
1641 EXPECT_EQ(observer.last_navigation_url(), http_url);
1642 EXPECT_TRUE(observer.last_navigation_succeeded());
1646 // Load server-redirect page pointing to a cross-site server-redirect page,
1647 // which eventually redirects back to cross-site page.
1648 GURL server_redirect_https_url(https_server.GetURL(
1649 "server-redirect?" + https_url.spec()));
1650 GURL server_redirect_http_url(test_server()->GetURL(
1651 "server-redirect?" + server_redirect_https_url.spec()));
1652 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1653 server_redirect_http_url));
1655 // DidFailProvisionalLoad when navigating to https_url.
1656 EXPECT_EQ(observer.last_navigation_url(), https_url);
1657 EXPECT_FALSE(observer.last_navigation_succeeded());
1661 // Load server-redirect page pointing to a cross-site client-redirect page,
1662 // which eventually redirects back to same-site page.
1663 GURL client_redirect_http_url(https_server.GetURL(
1664 "client-redirect?" + http_url.spec()));
1665 GURL server_redirect_http_url(test_server()->GetURL(
1666 "server-redirect?" + client_redirect_http_url.spec()));
1667 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1668 server_redirect_http_url));
1670 // DidFailProvisionalLoad when navigating to client_redirect_http_url.
1671 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
1672 EXPECT_FALSE(observer.last_navigation_succeeded());
1676 // Ensure that when navigating a frame cross-process RenderFrameProxyHosts are
1677 // created in the FrameTree skipping the subtree of the navigating frame.
1678 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1679 ProxyCreationSkipsSubtree) {
1680 GURL main_url(embedded_test_server()->GetURL(
1681 "a.com", "/cross_site_iframe_factory.html?a(a,a(a,a(a)))"));
1682 NavigateToURL(shell(), main_url);
1684 // It is safe to obtain the root frame tree node here, as it doesn't change.
1685 FrameTreeNode* root =
1686 static_cast<WebContentsImpl*>(shell()->web_contents())->
1687 GetFrameTree()->root();
1689 EXPECT_TRUE(root->child_at(1) != NULL);
1690 EXPECT_EQ(2U, root->child_at(1)->child_count());
1693 // Load same-site page into iframe.
1694 TestNavigationObserver observer(shell()->web_contents());
1695 GURL http_url(embedded_test_server()->GetURL("a.com", "/title1.html"));
1696 NavigateFrameToURL(root->child_at(0), http_url);
1697 EXPECT_EQ(http_url, observer.last_navigation_url());
1698 EXPECT_TRUE(observer.last_navigation_succeeded());
1699 EXPECT_EQ(
1700 " Site A\n"
1701 " |--Site A\n"
1702 " +--Site A\n"
1703 " |--Site A\n"
1704 " +--Site A\n"
1705 " +--Site A\n"
1706 "Where A = http://a.com/",
1707 DepictFrameTree(root));
1710 // Create the cross-site URL to navigate to.
1711 GURL cross_site_url =
1712 embedded_test_server()->GetURL("foo.com", "/frame_tree/title2.html");
1714 // Load cross-site page into the second iframe without waiting for the
1715 // navigation to complete. Once LoadURLWithParams returns, we would expect
1716 // proxies to have been created in the frame tree, but children of the
1717 // navigating frame to still be present. The reason is that we don't run the
1718 // message loop, so no IPCs that alter the frame tree can be processed.
1719 FrameTreeNode* child = root->child_at(1);
1720 SiteInstance* site = NULL;
1721 bool browser_side_navigation =
1722 base::CommandLine::ForCurrentProcess()->HasSwitch(
1723 switches::kEnableBrowserSideNavigation);
1724 std::string cross_site_rfh_type =
1725 browser_side_navigation ? "speculative" : "pending";
1727 TestNavigationObserver observer(shell()->web_contents());
1728 TestFrameNavigationObserver navigation_observer(child);
1729 NavigationController::LoadURLParams params(cross_site_url);
1730 params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
1731 params.frame_tree_node_id = child->frame_tree_node_id();
1732 child->navigator()->GetController()->LoadURLWithParams(params);
1734 if (browser_side_navigation) {
1735 site = child->render_manager()
1736 ->speculative_frame_host()
1737 ->GetSiteInstance();
1738 } else {
1739 site = child->render_manager()->pending_frame_host()->GetSiteInstance();
1741 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site);
1743 std::string tree = base::StringPrintf(
1744 " Site A ------------ proxies for B\n"
1745 " |--Site A ------- proxies for B\n"
1746 " +--Site A (B %s)\n"
1747 " |--Site A\n"
1748 " +--Site A\n"
1749 " +--Site A\n"
1750 "Where A = http://a.com/\n"
1751 " B = http://foo.com/",
1752 cross_site_rfh_type.c_str());
1753 EXPECT_EQ(tree, DepictFrameTree(root));
1755 // Now that the verification is done, run the message loop and wait for the
1756 // navigation to complete.
1757 navigation_observer.Wait();
1758 EXPECT_FALSE(child->render_manager()->pending_frame_host());
1759 EXPECT_TRUE(observer.last_navigation_succeeded());
1760 EXPECT_EQ(cross_site_url, observer.last_navigation_url());
1762 EXPECT_EQ(
1763 " Site A ------------ proxies for B\n"
1764 " |--Site A ------- proxies for B\n"
1765 " +--Site B ------- proxies for A\n"
1766 "Where A = http://a.com/\n"
1767 " B = http://foo.com/",
1768 DepictFrameTree(root));
1771 // Load another cross-site page into the same iframe.
1772 cross_site_url = embedded_test_server()->GetURL("bar.com", "/title3.html");
1774 // Perform the same checks as the first cross-site navigation, since
1775 // there have been issues in subsequent cross-site navigations. Also ensure
1776 // that the SiteInstance has properly changed.
1777 // TODO(nasko): Once we have proper cleanup of resources, add code to
1778 // verify that the intermediate SiteInstance/RenderFrameHost have been
1779 // properly cleaned up.
1780 TestNavigationObserver observer(shell()->web_contents());
1781 TestFrameNavigationObserver navigation_observer(child);
1782 NavigationController::LoadURLParams params(cross_site_url);
1783 params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
1784 params.frame_tree_node_id = child->frame_tree_node_id();
1785 child->navigator()->GetController()->LoadURLWithParams(params);
1787 SiteInstance* site2;
1788 if (browser_side_navigation) {
1789 site2 = child->render_manager()
1790 ->speculative_frame_host()
1791 ->GetSiteInstance();
1792 } else {
1793 site2 = child->render_manager()->pending_frame_host()->GetSiteInstance();
1795 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site2);
1796 EXPECT_NE(site, site2);
1798 std::string tree = base::StringPrintf(
1799 " Site A ------------ proxies for B C\n"
1800 " |--Site A ------- proxies for B C\n"
1801 " +--Site B (C %s) -- proxies for A\n"
1802 "Where A = http://a.com/\n"
1803 " B = http://foo.com/\n"
1804 " C = http://bar.com/",
1805 cross_site_rfh_type.c_str());
1806 EXPECT_EQ(tree, DepictFrameTree(root));
1808 navigation_observer.Wait();
1809 EXPECT_TRUE(observer.last_navigation_succeeded());
1810 EXPECT_EQ(cross_site_url, observer.last_navigation_url());
1811 EXPECT_EQ(0U, child->child_count());
1815 // Verify origin replication with an A-embed-B-embed-C-embed-A hierarchy.
1816 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OriginReplication) {
1817 GURL main_url(embedded_test_server()->GetURL(
1818 "a.com", "/cross_site_iframe_factory.html?a(b(c(a),b), a)"));
1819 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1821 // It is safe to obtain the root frame tree node here, as it doesn't change.
1822 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1823 ->GetFrameTree()
1824 ->root();
1826 EXPECT_EQ(
1827 " Site A ------------ proxies for B C\n"
1828 " |--Site B ------- proxies for A C\n" // tiptop_child
1829 " | |--Site C -- proxies for A B\n" // middle_child
1830 " | | +--Site A -- proxies for B C\n" // lowest_child
1831 " | +--Site B -- proxies for A C\n"
1832 " +--Site A ------- proxies for B C\n"
1833 "Where A = http://a.com/\n"
1834 " B = http://b.com/\n"
1835 " C = http://c.com/",
1836 DepictFrameTree(root));
1838 std::string a_origin = embedded_test_server()->GetURL("a.com", "/").spec();
1839 std::string b_origin = embedded_test_server()->GetURL("b.com", "/").spec();
1840 std::string c_origin = embedded_test_server()->GetURL("c.com", "/").spec();
1841 FrameTreeNode* tiptop_child = root->child_at(0);
1842 FrameTreeNode* middle_child = root->child_at(0)->child_at(0);
1843 FrameTreeNode* lowest_child = root->child_at(0)->child_at(0)->child_at(0);
1845 // Check that b.com frame's location.ancestorOrigins contains the correct
1846 // origin for the parent. The origin should have been replicated as part of
1847 // the ViewMsg_New message that created the parent's RenderFrameProxy in
1848 // b.com's process.
1849 int ancestor_origins_length = 0;
1850 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1851 tiptop_child->current_frame_host(),
1852 "window.domAutomationController.send(location.ancestorOrigins.length);",
1853 &ancestor_origins_length));
1854 EXPECT_EQ(1, ancestor_origins_length);
1855 std::string result;
1856 EXPECT_TRUE(ExecuteScriptAndExtractString(
1857 tiptop_child->current_frame_host(),
1858 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1859 &result));
1860 EXPECT_EQ(a_origin, result + "/");
1862 // Check that c.com frame's location.ancestorOrigins contains the correct
1863 // origin for its two ancestors. The topmost parent origin should be
1864 // replicated as part of ViewMsg_New, and the middle frame (b.com's) origin
1865 // should be replicated as part of FrameMsg_NewFrameProxy sent for b.com's
1866 // frame in c.com's process.
1867 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1868 middle_child->current_frame_host(),
1869 "window.domAutomationController.send(location.ancestorOrigins.length);",
1870 &ancestor_origins_length));
1871 EXPECT_EQ(2, ancestor_origins_length);
1872 EXPECT_TRUE(ExecuteScriptAndExtractString(
1873 middle_child->current_frame_host(),
1874 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1875 &result));
1876 EXPECT_EQ(b_origin, result + "/");
1877 EXPECT_TRUE(ExecuteScriptAndExtractString(
1878 middle_child->current_frame_host(),
1879 "window.domAutomationController.send(location.ancestorOrigins[1]);",
1880 &result));
1881 EXPECT_EQ(a_origin, result + "/");
1883 // Check that the nested a.com frame's location.ancestorOrigins contains the
1884 // correct origin for its three ancestors.
1885 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1886 lowest_child->current_frame_host(),
1887 "window.domAutomationController.send(location.ancestorOrigins.length);",
1888 &ancestor_origins_length));
1889 EXPECT_EQ(3, ancestor_origins_length);
1890 EXPECT_TRUE(ExecuteScriptAndExtractString(
1891 lowest_child->current_frame_host(),
1892 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1893 &result));
1894 EXPECT_EQ(c_origin, result + "/");
1895 EXPECT_TRUE(ExecuteScriptAndExtractString(
1896 lowest_child->current_frame_host(),
1897 "window.domAutomationController.send(location.ancestorOrigins[1]);",
1898 &result));
1899 EXPECT_EQ(b_origin, result + "/");
1900 EXPECT_TRUE(ExecuteScriptAndExtractString(
1901 lowest_child->current_frame_host(),
1902 "window.domAutomationController.send(location.ancestorOrigins[2]);",
1903 &result));
1904 EXPECT_EQ(a_origin, result + "/");
1907 // Check that iframe sandbox flags are replicated correctly.
1908 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SandboxFlagsReplication) {
1909 GURL main_url(embedded_test_server()->GetURL("/sandboxed_frames.html"));
1910 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1912 // It is safe to obtain the root frame tree node here, as it doesn't change.
1913 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1914 ->GetFrameTree()
1915 ->root();
1917 TestNavigationObserver observer(shell()->web_contents());
1919 // Navigate the second (sandboxed) subframe to a cross-site page with a
1920 // subframe.
1921 GURL foo_url(
1922 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
1923 NavigateFrameToURL(root->child_at(1), foo_url);
1924 EXPECT_TRUE(WaitForLoadStop(shell()->web_contents()));
1926 // We can't use a TestNavigationObserver to verify the URL here,
1927 // since the frame has children that may have clobbered it in the observer.
1928 EXPECT_EQ(foo_url, root->child_at(1)->current_url());
1930 // Load cross-site page into subframe's subframe.
1931 ASSERT_EQ(2U, root->child_at(1)->child_count());
1932 GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
1933 NavigateFrameToURL(root->child_at(1)->child_at(0), bar_url);
1934 EXPECT_TRUE(observer.last_navigation_succeeded());
1935 EXPECT_EQ(bar_url, observer.last_navigation_url());
1937 // Opening a popup in the sandboxed foo.com iframe should fail.
1938 bool success = false;
1939 EXPECT_TRUE(
1940 ExecuteScriptAndExtractBool(root->child_at(1)->current_frame_host(),
1941 "window.domAutomationController.send("
1942 "!window.open('data:text/html,dataurl'));",
1943 &success));
1944 EXPECT_TRUE(success);
1945 EXPECT_EQ(1u, Shell::windows().size());
1947 // Opening a popup in a frame whose parent is sandboxed should also fail.
1948 // Here, bar.com frame's sandboxed parent frame is a remote frame in
1949 // bar.com's process.
1950 success = false;
1951 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1952 root->child_at(1)->child_at(0)->current_frame_host(),
1953 "window.domAutomationController.send("
1954 "!window.open('data:text/html,dataurl'));",
1955 &success));
1956 EXPECT_TRUE(success);
1957 EXPECT_EQ(1u, Shell::windows().size());
1959 // Same, but now try the case where bar.com frame's sandboxed parent is a
1960 // local frame in bar.com's process.
1961 success = false;
1962 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1963 root->child_at(2)->child_at(0)->current_frame_host(),
1964 "window.domAutomationController.send("
1965 "!window.open('data:text/html,dataurl'));",
1966 &success));
1967 EXPECT_TRUE(success);
1968 EXPECT_EQ(1u, Shell::windows().size());
1970 // Check that foo.com frame's location.ancestorOrigins contains the correct
1971 // origin for the parent, which should be unaffected by sandboxing.
1972 int ancestor_origins_length = 0;
1973 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1974 root->child_at(1)->current_frame_host(),
1975 "window.domAutomationController.send(location.ancestorOrigins.length);",
1976 &ancestor_origins_length));
1977 EXPECT_EQ(1, ancestor_origins_length);
1978 std::string result;
1979 EXPECT_TRUE(ExecuteScriptAndExtractString(
1980 root->child_at(1)->current_frame_host(),
1981 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1982 &result));
1983 EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
1985 // Now check location.ancestorOrigins for the bar.com frame. The middle frame
1986 // (foo.com's) origin should be unique, since that frame is sandboxed, and
1987 // the top frame should match |main_url|.
1988 FrameTreeNode* bottom_child = root->child_at(1)->child_at(0);
1989 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1990 bottom_child->current_frame_host(),
1991 "window.domAutomationController.send(location.ancestorOrigins.length);",
1992 &ancestor_origins_length));
1993 EXPECT_EQ(2, ancestor_origins_length);
1994 EXPECT_TRUE(ExecuteScriptAndExtractString(
1995 bottom_child->current_frame_host(),
1996 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1997 &result));
1998 EXPECT_EQ("null", result);
1999 EXPECT_TRUE(ExecuteScriptAndExtractString(
2000 bottom_child->current_frame_host(),
2001 "window.domAutomationController.send(location.ancestorOrigins[1]);",
2002 &result));
2003 EXPECT_EQ(main_url.GetOrigin().spec(), result + "/");
2006 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
2007 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicSandboxFlags) {
2008 GURL main_url(
2009 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
2010 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2012 // It is safe to obtain the root frame tree node here, as it doesn't change.
2013 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2014 ->GetFrameTree()
2015 ->root();
2017 TestNavigationObserver observer(shell()->web_contents());
2018 ASSERT_EQ(2U, root->child_count());
2020 // Make sure first frame starts out at the correct cross-site page.
2021 EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"),
2022 root->child_at(0)->current_url());
2024 // Navigate second frame to another cross-site page.
2025 GURL baz_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
2026 NavigateFrameToURL(root->child_at(1), baz_url);
2027 EXPECT_TRUE(observer.last_navigation_succeeded());
2028 EXPECT_EQ(baz_url, observer.last_navigation_url());
2030 // Both frames should not be sandboxed to start with.
2031 EXPECT_EQ(blink::WebSandboxFlags::None,
2032 root->child_at(0)->current_replication_state().sandbox_flags);
2033 EXPECT_EQ(blink::WebSandboxFlags::None,
2034 root->child_at(0)->effective_sandbox_flags());
2035 EXPECT_EQ(blink::WebSandboxFlags::None,
2036 root->child_at(1)->current_replication_state().sandbox_flags);
2037 EXPECT_EQ(blink::WebSandboxFlags::None,
2038 root->child_at(1)->effective_sandbox_flags());
2040 // Dynamically update sandbox flags for the first frame.
2041 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
2042 "window.domAutomationController.send("
2043 "document.querySelector('iframe').sandbox="
2044 "'allow-scripts');"));
2046 // Check that updated sandbox flags are propagated to browser process.
2047 // The new flags should be set in current_replication_state(), while
2048 // effective_sandbox_flags() should still reflect the old flags, because
2049 // sandbox flag updates take place only after navigations. "allow-scripts"
2050 // resets both SandboxFlags::Scripts and SandboxFlags::AutomaticFeatures bits
2051 // per blink::parseSandboxPolicy().
2052 blink::WebSandboxFlags expected_flags =
2053 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
2054 ~blink::WebSandboxFlags::AutomaticFeatures;
2055 EXPECT_EQ(expected_flags,
2056 root->child_at(0)->current_replication_state().sandbox_flags);
2057 EXPECT_EQ(blink::WebSandboxFlags::None,
2058 root->child_at(0)->effective_sandbox_flags());
2060 // Navigate the first frame to a page on the same site. The new sandbox
2061 // flags should take effect.
2062 GURL bar_url(
2063 embedded_test_server()->GetURL("bar.com", "/frame_tree/2-4.html"));
2064 NavigateFrameToURL(root->child_at(0), bar_url);
2065 // (The new page has a subframe; wait for it to load as well.)
2066 ASSERT_TRUE(WaitForLoadStop(shell()->web_contents()));
2067 EXPECT_EQ(bar_url, root->child_at(0)->current_url());
2068 ASSERT_EQ(1U, root->child_at(0)->child_count());
2070 EXPECT_EQ(
2071 " Site A ------------ proxies for B C\n"
2072 " |--Site B ------- proxies for A C\n"
2073 " | +--Site B -- proxies for A C\n"
2074 " +--Site C ------- proxies for A B\n"
2075 "Where A = http://127.0.0.1/\n"
2076 " B = http://bar.com/\n"
2077 " C = http://baz.com/",
2078 DepictFrameTree(root));
2080 // Confirm that the browser process has updated the frame's current sandbox
2081 // flags.
2082 EXPECT_EQ(expected_flags,
2083 root->child_at(0)->current_replication_state().sandbox_flags);
2084 EXPECT_EQ(expected_flags, root->child_at(0)->effective_sandbox_flags());
2086 // Opening a popup in the now-sandboxed frame should fail.
2087 bool success = false;
2088 EXPECT_TRUE(
2089 ExecuteScriptAndExtractBool(root->child_at(0)->current_frame_host(),
2090 "window.domAutomationController.send("
2091 "!window.open('data:text/html,dataurl'));",
2092 &success));
2093 EXPECT_TRUE(success);
2094 EXPECT_EQ(1u, Shell::windows().size());
2096 // Navigate the child of the now-sandboxed frame to a page on baz.com. The
2097 // child should inherit the latest sandbox flags from its parent frame, which
2098 // is currently a proxy in baz.com's renderer process. This checks that the
2099 // proxies of |root->child_at(0)| were also updated with the latest sandbox
2100 // flags.
2101 GURL baz_child_url(embedded_test_server()->GetURL("baz.com", "/title2.html"));
2102 NavigateFrameToURL(root->child_at(0)->child_at(0), baz_child_url);
2103 EXPECT_TRUE(observer.last_navigation_succeeded());
2104 EXPECT_EQ(baz_child_url, observer.last_navigation_url());
2106 EXPECT_EQ(
2107 " Site A ------------ proxies for B C\n"
2108 " |--Site B ------- proxies for A C\n"
2109 " | +--Site C -- proxies for A B\n"
2110 " +--Site C ------- proxies for A B\n"
2111 "Where A = http://127.0.0.1/\n"
2112 " B = http://bar.com/\n"
2113 " C = http://baz.com/",
2114 DepictFrameTree(root));
2116 // Opening a popup in the child of a sandboxed frame should fail.
2117 success = false;
2118 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2119 root->child_at(0)->child_at(0)->current_frame_host(),
2120 "window.domAutomationController.send("
2121 "!window.open('data:text/html,dataurl'));",
2122 &success));
2123 EXPECT_TRUE(success);
2124 EXPECT_EQ(1u, Shell::windows().size());
2127 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
2128 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2129 DynamicSandboxFlagsRemoteToLocal) {
2130 GURL main_url(
2131 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
2132 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2134 // It is safe to obtain the root frame tree node here, as it doesn't change.
2135 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2136 ->GetFrameTree()
2137 ->root();
2139 TestNavigationObserver observer(shell()->web_contents());
2140 ASSERT_EQ(2U, root->child_count());
2142 // Make sure the two frames starts out at correct URLs.
2143 EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"),
2144 root->child_at(0)->current_url());
2145 EXPECT_EQ(embedded_test_server()->GetURL("/title1.html"),
2146 root->child_at(1)->current_url());
2148 // Update the second frame's sandbox flags.
2149 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
2150 "window.domAutomationController.send("
2151 "document.querySelectorAll('iframe')[1].sandbox="
2152 "'allow-scripts');"));
2154 // Check that the current sandbox flags are updated but the effective
2155 // sandbox flags are not.
2156 blink::WebSandboxFlags expected_flags =
2157 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
2158 ~blink::WebSandboxFlags::AutomaticFeatures;
2159 EXPECT_EQ(expected_flags,
2160 root->child_at(1)->current_replication_state().sandbox_flags);
2161 EXPECT_EQ(blink::WebSandboxFlags::None,
2162 root->child_at(1)->effective_sandbox_flags());
2164 // Navigate the second subframe to a page on bar.com. This will trigger a
2165 // remote-to-local frame swap in bar.com's process. The target page has
2166 // another frame, so use TestFrameNavigationObserver to wait for all frames
2167 // to be loaded.
2168 TestFrameNavigationObserver frame_observer(root->child_at(1), 2);
2169 GURL bar_url(embedded_test_server()->GetURL(
2170 "bar.com", "/frame_tree/page_with_one_frame.html"));
2171 NavigateFrameToURL(root->child_at(1), bar_url);
2172 frame_observer.Wait();
2173 EXPECT_EQ(bar_url, root->child_at(1)->current_url());
2174 ASSERT_EQ(1U, root->child_at(1)->child_count());
2176 // Confirm that the browser process has updated the current sandbox flags.
2177 EXPECT_EQ(expected_flags,
2178 root->child_at(1)->current_replication_state().sandbox_flags);
2179 EXPECT_EQ(expected_flags, root->child_at(1)->effective_sandbox_flags());
2181 // Opening a popup in the sandboxed second frame should fail.
2182 bool success = false;
2183 EXPECT_TRUE(
2184 ExecuteScriptAndExtractBool(root->child_at(1)->current_frame_host(),
2185 "window.domAutomationController.send("
2186 "!window.open('data:text/html,dataurl'));",
2187 &success));
2188 EXPECT_TRUE(success);
2189 EXPECT_EQ(1u, Shell::windows().size());
2191 // Make sure that the child frame inherits the sandbox flags of its
2192 // now-sandboxed parent frame.
2193 success = false;
2194 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2195 root->child_at(1)->child_at(0)->current_frame_host(),
2196 "window.domAutomationController.send("
2197 "!window.open('data:text/html,dataurl'));",
2198 &success));
2199 EXPECT_TRUE(success);
2200 EXPECT_EQ(1u, Shell::windows().size());
2203 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
2204 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2205 DynamicSandboxFlagsRendererInitiatedNavigation) {
2206 GURL main_url(
2207 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
2208 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2210 // It is safe to obtain the root frame tree node here, as it doesn't change.
2211 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2212 ->GetFrameTree()
2213 ->root();
2215 TestNavigationObserver observer(shell()->web_contents());
2216 ASSERT_EQ(1U, root->child_count());
2218 // Make sure the frame starts out at the correct cross-site page.
2219 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"),
2220 root->child_at(0)->current_url());
2222 // The frame should not be sandboxed to start with.
2223 EXPECT_EQ(blink::WebSandboxFlags::None,
2224 root->child_at(0)->current_replication_state().sandbox_flags);
2225 EXPECT_EQ(blink::WebSandboxFlags::None,
2226 root->child_at(0)->effective_sandbox_flags());
2228 // Dynamically update the frame's sandbox flags.
2229 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
2230 "window.domAutomationController.send("
2231 "document.querySelector('iframe').sandbox="
2232 "'allow-scripts');"));
2234 // Check that updated sandbox flags are propagated to browser process.
2235 // The new flags should be set in current_replication_state(), while
2236 // effective_sandbox_flags() should still reflect the old flags, because
2237 // sandbox flag updates take place only after navigations. "allow-scripts"
2238 // resets both SandboxFlags::Scripts and SandboxFlags::AutomaticFeatures bits
2239 // per blink::parseSandboxPolicy().
2240 blink::WebSandboxFlags expected_flags =
2241 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
2242 ~blink::WebSandboxFlags::AutomaticFeatures;
2243 EXPECT_EQ(expected_flags,
2244 root->child_at(0)->current_replication_state().sandbox_flags);
2245 EXPECT_EQ(blink::WebSandboxFlags::None,
2246 root->child_at(0)->effective_sandbox_flags());
2248 // Perform a renderer-initiated same-site navigation in the first frame. The
2249 // new sandbox flags should take effect.
2250 TestFrameNavigationObserver frame_observer(root->child_at(0));
2251 ASSERT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
2252 "window.location.href='/title2.html'"));
2253 frame_observer.Wait();
2254 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title2.html"),
2255 root->child_at(0)->current_url());
2257 // Confirm that the browser process has updated the frame's current sandbox
2258 // flags.
2259 EXPECT_EQ(expected_flags,
2260 root->child_at(0)->current_replication_state().sandbox_flags);
2261 EXPECT_EQ(expected_flags, root->child_at(0)->effective_sandbox_flags());
2263 // Opening a popup in the now-sandboxed frame should fail.
2264 bool success = false;
2265 EXPECT_TRUE(
2266 ExecuteScriptAndExtractBool(root->child_at(0)->current_frame_host(),
2267 "window.domAutomationController.send("
2268 "!window.open('data:text/html,dataurl'));",
2269 &success));
2270 EXPECT_TRUE(success);
2271 EXPECT_EQ(1u, Shell::windows().size());
2274 // Verify that when a new child frame is added, the proxies created for it in
2275 // other SiteInstances have correct sandbox flags and origin.
2277 // A A A
2278 // / / \ / \ .
2279 // B -> B A -> B A
2280 // \ .
2281 // B
2283 // The test checks sandbox flags and origin for the proxy added in step 2, by
2284 // checking whether the grandchild frame added in step 3 sees proper sandbox
2285 // flags and origin for its (remote) parent. This wasn't addressed when
2286 // https://crbug.com/423587 was fixed.
2287 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2288 ProxiesForNewChildFramesHaveCorrectReplicationState) {
2289 GURL main_url(
2290 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
2291 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2293 // It is safe to obtain the root frame tree node here, as it doesn't change.
2294 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2295 ->GetFrameTree()
2296 ->root();
2297 TestNavigationObserver observer(shell()->web_contents());
2299 EXPECT_EQ(
2300 " Site A ------------ proxies for B\n"
2301 " +--Site B ------- proxies for A\n"
2302 "Where A = http://127.0.0.1/\n"
2303 " B = http://baz.com/",
2304 DepictFrameTree(root));
2306 // In the root frame, add a new sandboxed local frame, which itself has a
2307 // child frame on baz.com. Wait for three RenderFrameHosts to be created:
2308 // the new sandboxed local frame, its child (while it's still local), and a
2309 // pending RFH when starting the cross-site navigation to baz.com.
2310 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 3);
2311 EXPECT_TRUE(
2312 ExecuteScript(root->current_frame_host(),
2313 "window.domAutomationController.send("
2314 " addFrame('/frame_tree/page_with_one_frame.html',"
2315 " 'allow-scripts allow-same-origin'))"));
2316 frame_observer.Wait();
2318 // Wait for the cross-site navigation to baz.com in the grandchild to finish.
2319 FrameTreeNode* bottom_child = root->child_at(1)->child_at(0);
2320 TestFrameNavigationObserver navigation_observer(bottom_child);
2321 navigation_observer.Wait();
2323 EXPECT_EQ(
2324 " Site A ------------ proxies for B\n"
2325 " |--Site B ------- proxies for A\n"
2326 " +--Site A ------- proxies for B\n"
2327 " +--Site B -- proxies for A\n"
2328 "Where A = http://127.0.0.1/\n"
2329 " B = http://baz.com/",
2330 DepictFrameTree(root));
2332 // Use location.ancestorOrigins to check that the grandchild on baz.com sees
2333 // correct origin for its parent.
2334 int ancestor_origins_length = 0;
2335 EXPECT_TRUE(ExecuteScriptAndExtractInt(
2336 bottom_child->current_frame_host(),
2337 "window.domAutomationController.send(location.ancestorOrigins.length);",
2338 &ancestor_origins_length));
2339 EXPECT_EQ(2, ancestor_origins_length);
2340 std::string parent_origin;
2341 EXPECT_TRUE(ExecuteScriptAndExtractString(
2342 bottom_child->current_frame_host(),
2343 "window.domAutomationController.send(location.ancestorOrigins[0]);",
2344 &parent_origin));
2345 EXPECT_EQ(main_url.GetOrigin().spec(), parent_origin + "/");
2347 // Check that the sandbox flags in the browser process are correct.
2348 // "allow-scripts" resets both WebSandboxFlags::Scripts and
2349 // WebSandboxFlags::AutomaticFeatures bits per blink::parseSandboxPolicy().
2350 blink::WebSandboxFlags expected_flags =
2351 blink::WebSandboxFlags::All & ~blink::WebSandboxFlags::Scripts &
2352 ~blink::WebSandboxFlags::AutomaticFeatures &
2353 ~blink::WebSandboxFlags::Origin;
2354 EXPECT_EQ(expected_flags,
2355 root->child_at(1)->current_replication_state().sandbox_flags);
2357 // The child of the sandboxed frame should've inherited sandbox flags, so it
2358 // should not be able to create popups.
2359 bool success = false;
2360 EXPECT_TRUE(
2361 ExecuteScriptAndExtractBool(bottom_child->current_frame_host(),
2362 "window.domAutomationController.send("
2363 "!window.open('data:text/html,dataurl'));",
2364 &success));
2365 EXPECT_TRUE(success);
2366 EXPECT_EQ(1u, Shell::windows().size());
2369 // Verify that a child frame can retrieve the name property set by its parent.
2370 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, WindowNameReplication) {
2371 GURL main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html"));
2372 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2374 // It is safe to obtain the root frame tree node here, as it doesn't change.
2375 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2376 ->GetFrameTree()
2377 ->root();
2379 TestNavigationObserver observer(shell()->web_contents());
2381 // Load cross-site page into iframe.
2382 GURL frame_url =
2383 embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html");
2384 NavigateFrameToURL(root->child_at(0), frame_url);
2385 EXPECT_TRUE(observer.last_navigation_succeeded());
2386 EXPECT_EQ(frame_url, observer.last_navigation_url());
2388 // Ensure that a new process is created for the subframe.
2389 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
2390 root->child_at(0)->current_frame_host()->GetSiteInstance());
2392 // Check that the window.name seen by the frame matches the name attribute
2393 // specified by its parent in the iframe tag.
2394 std::string result;
2395 EXPECT_TRUE(ExecuteScriptAndExtractString(
2396 root->child_at(0)->current_frame_host(),
2397 "window.domAutomationController.send(window.name);", &result));
2398 EXPECT_EQ("3-1-name", result);
2401 // Verify that dynamic updates to a frame's window.name propagate to the
2402 // frame's proxies, so that the latest frame names can be used in navigations.
2403 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicWindowName) {
2404 GURL main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html"));
2405 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2407 // It is safe to obtain the root frame tree node here, as it doesn't change.
2408 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2409 ->GetFrameTree()
2410 ->root();
2411 TestNavigationObserver observer(shell()->web_contents());
2413 // Load cross-site page into iframe.
2414 GURL frame_url =
2415 embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html");
2416 NavigateFrameToURL(root->child_at(0), frame_url);
2417 EXPECT_TRUE(observer.last_navigation_succeeded());
2418 EXPECT_EQ(frame_url, observer.last_navigation_url());
2420 // Browser process should know the child frame's original window.name
2421 // specified in the iframe element.
2422 EXPECT_EQ(root->child_at(0)->frame_name(), "3-1-name");
2424 // Update the child frame's window.name.
2425 EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
2426 "window.domAutomationController.send("
2427 "window.name = 'updated-name');"));
2429 // The change should propagate to the browser process.
2430 EXPECT_EQ(root->child_at(0)->frame_name(), "updated-name");
2432 // The proxy in the parent process should also receive the updated name.
2433 // Check that it can reference the child frame by its new name.
2434 bool success = false;
2435 EXPECT_TRUE(
2436 ExecuteScriptAndExtractBool(shell()->web_contents(),
2437 "window.domAutomationController.send("
2438 "frames['updated-name'] == frames[0]);",
2439 &success));
2440 EXPECT_TRUE(success);
2442 // Issue a renderer-initiated navigation from the root frame to the child
2443 // frame using the frame's name. Make sure correct frame is navigated.
2445 // TODO(alexmos): When blink::createWindow is refactored to handle
2446 // RemoteFrames, this should also be tested via window.open(url, frame_name)
2447 // and a more complicated frame hierarchy (https://crbug.com/463742)
2448 TestFrameNavigationObserver frame_observer(root->child_at(0));
2449 GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
2450 std::string script = base::StringPrintf(
2451 "window.domAutomationController.send("
2452 "frames['updated-name'].location.href = '%s');",
2453 foo_url.spec().c_str());
2454 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), script));
2455 frame_observer.Wait();
2456 EXPECT_EQ(foo_url, root->child_at(0)->current_url());
2459 // Verify that when a frame is navigated to a new origin, the origin update
2460 // propagates to the frame's proxies.
2461 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OriginUpdatesReachProxies) {
2462 GURL main_url(
2463 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
2464 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2466 // It is safe to obtain the root frame tree node here, as it doesn't change.
2467 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2468 ->GetFrameTree()
2469 ->root();
2470 TestNavigationObserver observer(shell()->web_contents());
2472 EXPECT_EQ(
2473 " Site A ------------ proxies for B\n"
2474 " |--Site B ------- proxies for A\n"
2475 " +--Site A ------- proxies for B\n"
2476 "Where A = http://127.0.0.1/\n"
2477 " B = http://bar.com/",
2478 DepictFrameTree(root));
2480 // Navigate second subframe to a baz.com. This should send an origin update
2481 // to the frame's proxy in the bar.com (first frame's) process.
2482 GURL frame_url = embedded_test_server()->GetURL("baz.com", "/title2.html");
2483 NavigateFrameToURL(root->child_at(1), frame_url);
2484 EXPECT_TRUE(observer.last_navigation_succeeded());
2485 EXPECT_EQ(frame_url, observer.last_navigation_url());
2487 // The first frame can't directly observe the second frame's origin with
2488 // JavaScript. Instead, try to navigate the second frame from the first
2489 // frame. This should fail with a console error message, which should
2490 // contain the second frame's updated origin (see blink::Frame::canNavigate).
2491 scoped_ptr<ConsoleObserverDelegate> console_delegate(
2492 new ConsoleObserverDelegate(
2493 shell()->web_contents(),
2494 "Unsafe JavaScript attempt to initiate navigation*"));
2495 shell()->web_contents()->SetDelegate(console_delegate.get());
2497 // frames[1] can't be used due to a bug where RemoteFrames are created out of
2498 // order (https://crbug.com/478792). Instead, target second frame by name.
2499 EXPECT_TRUE(ExecuteScript(
2500 root->child_at(0)->current_frame_host(),
2501 "window.domAutomationController.send("
2502 " parent.frames['frame2'].location.href = 'data:text/html,foo');"));
2503 console_delegate->Wait();
2505 std::string frame_origin =
2506 root->child_at(1)->current_replication_state().origin.Serialize();
2507 EXPECT_EQ(frame_origin + "/", frame_url.GetOrigin().spec());
2508 EXPECT_TRUE(
2509 base::MatchPattern(console_delegate->message(), "*" + frame_origin + "*"))
2510 << "Error message does not contain the frame's latest origin ("
2511 << frame_origin << ")";
2514 // Ensure that navigating subframes in --site-per-process mode properly fires
2515 // the DidStopLoading event on WebContentsObserver.
2516 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteDidStopLoading) {
2517 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
2518 NavigateToURL(shell(), main_url);
2520 // It is safe to obtain the root frame tree node here, as it doesn't change.
2521 FrameTreeNode* root =
2522 static_cast<WebContentsImpl*>(shell()->web_contents())->
2523 GetFrameTree()->root();
2525 TestNavigationObserver observer(shell()->web_contents());
2527 // Load same-site page into iframe.
2528 FrameTreeNode* child = root->child_at(0);
2529 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
2530 NavigateFrameToURL(child, http_url);
2531 EXPECT_EQ(http_url, observer.last_navigation_url());
2532 EXPECT_TRUE(observer.last_navigation_succeeded());
2534 // Load cross-site page into iframe.
2535 TestNavigationObserver nav_observer(shell()->web_contents(), 1);
2536 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
2537 NavigationController::LoadURLParams params(url);
2538 params.transition_type = ui::PAGE_TRANSITION_LINK;
2539 params.frame_tree_node_id = child->frame_tree_node_id();
2540 child->navigator()->GetController()->LoadURLWithParams(params);
2541 nav_observer.Wait();
2543 // Verify that the navigation succeeded and the expected URL was loaded.
2544 EXPECT_TRUE(observer.last_navigation_succeeded());
2545 EXPECT_EQ(url, observer.last_navigation_url());
2548 // Ensure that the renderer does not crash when navigating a frame that has a
2549 // sibling RemoteFrame. See https://crbug.com/426953.
2550 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2551 NavigateWithSiblingRemoteFrame) {
2552 GURL main_url(
2553 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
2554 NavigateToURL(shell(), main_url);
2556 // It is safe to obtain the root frame tree node here, as it doesn't change.
2557 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2558 ->GetFrameTree()
2559 ->root();
2560 TestNavigationObserver observer(shell()->web_contents());
2562 // Make sure the first frame is out of process.
2563 ASSERT_EQ(2U, root->child_count());
2564 FrameTreeNode* node2 = root->child_at(0);
2565 EXPECT_NE(root->current_frame_host()->GetSiteInstance(),
2566 node2->current_frame_host()->GetSiteInstance());
2568 // Make sure the second frame is in the parent's process.
2569 FrameTreeNode* node3 = root->child_at(1);
2570 EXPECT_EQ(root->current_frame_host()->GetSiteInstance(),
2571 node3->current_frame_host()->GetSiteInstance());
2573 // Navigate the second iframe (node3) to a URL in its own process.
2574 GURL title_url = embedded_test_server()->GetURL("/title2.html");
2575 NavigateFrameToURL(node3, title_url);
2576 EXPECT_TRUE(observer.last_navigation_succeeded());
2577 EXPECT_EQ(title_url, observer.last_navigation_url());
2578 EXPECT_EQ(root->current_frame_host()->GetSiteInstance(),
2579 node3->current_frame_host()->GetSiteInstance());
2580 EXPECT_TRUE(node3->current_frame_host()->IsRenderFrameLive());
2583 // Verify that load events for iframe elements work when the child frame is
2584 // out-of-process. In such cases, the load event is forwarded from the child
2585 // frame to the parent frame via the browser process.
2586 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, LoadEventForwarding) {
2587 // Load a page with a cross-site frame. The parent page has an onload
2588 // handler in the iframe element that appends "LOADED" to the document title.
2590 GURL main_url(
2591 embedded_test_server()->GetURL("/frame_with_load_event.html"));
2592 base::string16 expected_title(base::UTF8ToUTF16("LOADED"));
2593 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
2594 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2595 EXPECT_EQ(title_watcher.WaitAndGetTitle(), expected_title);
2598 // It is safe to obtain the root frame tree node here, as it doesn't change.
2599 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2600 ->GetFrameTree()
2601 ->root();
2603 // Load another cross-site page into the iframe and check that the load event
2604 // is fired.
2606 GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
2607 base::string16 expected_title(base::UTF8ToUTF16("LOADEDLOADED"));
2608 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
2609 TestNavigationObserver observer(shell()->web_contents());
2610 NavigateFrameToURL(root->child_at(0), foo_url);
2611 EXPECT_TRUE(observer.last_navigation_succeeded());
2612 EXPECT_EQ(foo_url, observer.last_navigation_url());
2613 EXPECT_EQ(title_watcher.WaitAndGetTitle(), expected_title);
2617 // Check that postMessage can be routed between cross-site iframes.
2618 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SubframePostMessage) {
2619 GURL main_url(embedded_test_server()->GetURL(
2620 "/frame_tree/page_with_post_message_frames.html"));
2621 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2623 // It is safe to obtain the root frame tree node here, as it doesn't change.
2624 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2625 ->GetFrameTree()
2626 ->root();
2628 ASSERT_EQ(2U, root->child_count());
2630 // Verify the frames start at correct URLs. First frame should be
2631 // same-site; second frame should be cross-site.
2632 GURL same_site_url(embedded_test_server()->GetURL("/post_message.html"));
2633 EXPECT_EQ(same_site_url, root->child_at(0)->current_url());
2634 GURL foo_url(embedded_test_server()->GetURL("foo.com",
2635 "/post_message.html"));
2636 EXPECT_EQ(foo_url, root->child_at(1)->current_url());
2637 EXPECT_NE(root->child_at(0)->current_frame_host()->GetSiteInstance(),
2638 root->child_at(1)->current_frame_host()->GetSiteInstance());
2640 // Send a message from first, same-site frame to second, cross-site frame.
2641 // Expect the second frame to reply back to the first frame.
2642 PostMessageAndWaitForReply(root->child_at(0),
2643 "postToSibling('subframe-msg','subframe2')",
2644 "\"done-subframe1\"");
2646 // Send a postMessage from second, cross-site frame to its parent. Expect
2647 // parent to send a reply to the frame.
2648 base::string16 expected_title(base::ASCIIToUTF16("subframe-msg"));
2649 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
2650 PostMessageAndWaitForReply(root->child_at(1), "postToParent('subframe-msg')",
2651 "\"done-subframe2\"");
2652 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
2654 // Verify the total number of received messages for each subframe. First
2655 // frame should have one message (reply from second frame). Second frame
2656 // should have two messages (message from first frame and reply from parent).
2657 // Parent should have one message (from second frame).
2658 EXPECT_EQ(1, GetReceivedMessages(root->child_at(0)));
2659 EXPECT_EQ(2, GetReceivedMessages(root->child_at(1)));
2660 EXPECT_EQ(1, GetReceivedMessages(root));
2663 // Check that postMessage can be sent from a subframe on a cross-process opener
2664 // tab, and that its event.source points to a valid proxy.
2665 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2666 PostMessageWithSubframeOnOpenerChain) {
2667 GURL main_url(embedded_test_server()->GetURL(
2668 "a.com", "/frame_tree/page_with_post_message_frames.html"));
2669 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2671 // It is safe to obtain the root frame tree node here, as it doesn't change.
2672 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2673 ->GetFrameTree()
2674 ->root();
2676 ASSERT_EQ(2U, root->child_count());
2678 // Verify the initial state of the world. First frame should be same-site;
2679 // second frame should be cross-site.
2680 EXPECT_EQ(
2681 " Site A ------------ proxies for B\n"
2682 " |--Site A ------- proxies for B\n"
2683 " +--Site B ------- proxies for A\n"
2684 "Where A = http://a.com/\n"
2685 " B = http://foo.com/",
2686 DepictFrameTree(root));
2688 // Open a popup from the first subframe (so that popup's window.opener points
2689 // to the subframe) and navigate it to bar.com.
2690 ShellAddedObserver new_shell_observer;
2691 EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
2692 "openPopup('about:blank');"));
2693 Shell* popup = new_shell_observer.GetShell();
2694 GURL popup_url(
2695 embedded_test_server()->GetURL("bar.com", "/post_message.html"));
2696 EXPECT_TRUE(NavigateToURL(popup, popup_url));
2698 // From the popup, open another popup for baz.com. This will be used to
2699 // check that the whole opener chain is processed when creating proxies and
2700 // not just an immediate opener.
2701 ShellAddedObserver new_shell_observer2;
2702 EXPECT_TRUE(
2703 ExecuteScript(popup->web_contents(), "openPopup('about:blank');"));
2704 Shell* popup2 = new_shell_observer2.GetShell();
2705 GURL popup2_url(
2706 embedded_test_server()->GetURL("baz.com", "/post_message.html"));
2707 EXPECT_TRUE(NavigateToURL(popup2, popup2_url));
2709 // Ensure that we've created proxies for SiteInstances of both popups (C, D)
2710 // in the main window's frame tree.
2711 EXPECT_EQ(
2712 " Site A ------------ proxies for B C D\n"
2713 " |--Site A ------- proxies for B C D\n"
2714 " +--Site B ------- proxies for A C D\n"
2715 "Where A = http://a.com/\n"
2716 " B = http://foo.com/\n"
2717 " C = http://bar.com/\n"
2718 " D = http://baz.com/",
2719 DepictFrameTree(root));
2721 // Check the first popup's frame tree as well. Note that it doesn't have a
2722 // proxy for foo.com, since foo.com can't reach the popup. It does have a
2723 // proxy for its opener a.com (which can reach it via the window.open
2724 // reference) and second popup (which can reach it via window.opener).
2725 FrameTreeNode* popup_root =
2726 static_cast<WebContentsImpl*>(popup->web_contents())
2727 ->GetFrameTree()
2728 ->root();
2729 EXPECT_EQ(
2730 " Site C ------------ proxies for A D\n"
2731 "Where A = http://a.com/\n"
2732 " C = http://bar.com/\n"
2733 " D = http://baz.com/",
2734 DepictFrameTree(popup_root));
2736 // Send a message from first subframe on main page to the first popup and
2737 // wait for a reply back. The reply verifies that the proxy for the opener
2738 // tab's subframe is targeted properly.
2739 PostMessageAndWaitForReply(root->child_at(0), "postToPopup('subframe-msg')",
2740 "\"done-subframe1\"");
2742 // Send a postMessage from the popup to window.opener and ensure that it
2743 // reaches subframe1. This verifies that the subframe opener information
2744 // propagated to the popup's RenderFrame. Wait for subframe1 to send a reply
2745 // message to the popup.
2746 EXPECT_TRUE(ExecuteScript(popup->web_contents(), "window.name = 'popup';"));
2747 PostMessageAndWaitForReply(popup_root, "postToOpener('subframe-msg', '*')",
2748 "\"done-popup\"");
2750 // Second a postMessage from popup2 to window.opener.opener, which should
2751 // resolve to subframe1. This tests opener chains of length greater than 1.
2752 // As before, subframe1 will send a reply to popup2.
2753 FrameTreeNode* popup2_root =
2754 static_cast<WebContentsImpl*>(popup2->web_contents())
2755 ->GetFrameTree()
2756 ->root();
2757 EXPECT_TRUE(ExecuteScript(popup2->web_contents(), "window.name = 'popup2';"));
2758 PostMessageAndWaitForReply(popup2_root,
2759 "postToOpenerOfOpener('subframe-msg', '*')",
2760 "\"done-popup2\"");
2762 // Verify the total number of received messages for each subframe:
2763 // - 3 for first subframe (two from first popup, one from second popup)
2764 // - 2 for popup (both from first subframe)
2765 // - 1 for popup2 (reply from first subframe)
2766 // - 0 for other frames
2767 EXPECT_EQ(0, GetReceivedMessages(root));
2768 EXPECT_EQ(3, GetReceivedMessages(root->child_at(0)));
2769 EXPECT_EQ(0, GetReceivedMessages(root->child_at(1)));
2770 EXPECT_EQ(2, GetReceivedMessages(popup_root));
2771 EXPECT_EQ(1, GetReceivedMessages(popup2_root));
2774 // Check that parent.frames[num] references correct sibling frames when the
2775 // parent is remote. See https://crbug.com/478792.
2776 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, IndexedFrameAccess) {
2777 // Start on a page with three same-site subframes.
2778 GURL main_url(
2779 embedded_test_server()->GetURL("a.com", "/frame_tree/top.html"));
2780 EXPECT_TRUE(NavigateToURL(shell(), main_url));
2782 // It is safe to obtain the root frame tree node here, as it doesn't change.
2783 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2784 ->GetFrameTree()
2785 ->root();
2786 ASSERT_EQ(3U, root->child_count());
2787 FrameTreeNode* child0 = root->child_at(0);
2788 FrameTreeNode* child1 = root->child_at(1);
2789 FrameTreeNode* child2 = root->child_at(2);
2791 // Send each of the frames to a different site. Each new renderer will first
2792 // create proxies for the parent and two sibling subframes and then create
2793 // and insert the new RenderFrame into the frame tree.
2794 GURL b_url(embedded_test_server()->GetURL("b.com", "/post_message.html"));
2795 GURL c_url(embedded_test_server()->GetURL("c.com", "/post_message.html"));
2796 GURL d_url(embedded_test_server()->GetURL("d.com", "/post_message.html"));
2797 NavigateFrameToURL(child0, b_url);
2798 // TODO(alexmos): The calls to WaitForRenderFrameReady can be removed once
2799 // TestFrameNavigationObserver is fixed to use DidFinishLoad.
2800 EXPECT_TRUE(WaitForRenderFrameReady(child0->current_frame_host()));
2801 NavigateFrameToURL(child1, c_url);
2802 EXPECT_TRUE(WaitForRenderFrameReady(child1->current_frame_host()));
2803 NavigateFrameToURL(child2, d_url);
2804 EXPECT_TRUE(WaitForRenderFrameReady(child2->current_frame_host()));
2806 EXPECT_EQ(
2807 " Site A ------------ proxies for B C D\n"
2808 " |--Site B ------- proxies for A C D\n"
2809 " |--Site C ------- proxies for A B D\n"
2810 " +--Site D ------- proxies for A B C\n"
2811 "Where A = http://a.com/\n"
2812 " B = http://b.com/\n"
2813 " C = http://c.com/\n"
2814 " D = http://d.com/",
2815 DepictFrameTree(root));
2817 // Check that each subframe sees itself at correct index in parent.frames.
2818 bool success = false;
2819 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2820 child0->current_frame_host(),
2821 "window.domAutomationController.send(window === parent.frames[0]);",
2822 &success));
2823 EXPECT_TRUE(success);
2825 success = false;
2826 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2827 child1->current_frame_host(),
2828 "window.domAutomationController.send(window === parent.frames[1]);",
2829 &success));
2830 EXPECT_TRUE(success);
2832 success = false;
2833 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2834 child2->current_frame_host(),
2835 "window.domAutomationController.send(window === parent.frames[2]);",
2836 &success));
2837 EXPECT_TRUE(success);
2839 // Send a postMessage from B to parent.frames[1], which should go to C, and
2840 // wait for reply.
2841 PostMessageAndWaitForReply(child0, "postToSibling('subframe-msg', 1)",
2842 "\"done-1-1-name\"");
2844 // Send a postMessage from C to parent.frames[2], which should go to D, and
2845 // wait for reply.
2846 PostMessageAndWaitForReply(child1, "postToSibling('subframe-msg', 2)",
2847 "\"done-1-2-name\"");
2849 // Verify the total number of received messages for each subframe.
2850 EXPECT_EQ(1, GetReceivedMessages(child0));
2851 EXPECT_EQ(2, GetReceivedMessages(child1));
2852 EXPECT_EQ(1, GetReceivedMessages(child2));
2855 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, RFPHDestruction) {
2856 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
2857 NavigateToURL(shell(), main_url);
2859 // It is safe to obtain the root frame tree node here, as it doesn't change.
2860 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2861 ->GetFrameTree()
2862 ->root();
2864 TestNavigationObserver observer(shell()->web_contents());
2866 // Load cross-site page into iframe.
2867 FrameTreeNode* child = root->child_at(0);
2868 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
2869 NavigateFrameToURL(root->child_at(0), url);
2870 EXPECT_TRUE(observer.last_navigation_succeeded());
2871 EXPECT_EQ(url, observer.last_navigation_url());
2872 EXPECT_EQ(
2873 " Site A ------------ proxies for B\n"
2874 " |--Site B ------- proxies for A\n"
2875 " +--Site A ------- proxies for B\n"
2876 " |--Site A -- proxies for B\n"
2877 " +--Site A -- proxies for B\n"
2878 " +--Site A -- proxies for B\n"
2879 "Where A = http://127.0.0.1/\n"
2880 " B = http://foo.com/",
2881 DepictFrameTree(root));
2883 // Load another cross-site page.
2884 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
2885 NavigateIframeToURL(shell()->web_contents(), "test", url);
2886 EXPECT_TRUE(observer.last_navigation_succeeded());
2887 EXPECT_EQ(url, observer.last_navigation_url());
2888 EXPECT_EQ(
2889 " Site A ------------ proxies for C\n"
2890 " |--Site C ------- proxies for A\n"
2891 " +--Site A ------- proxies for C\n"
2892 " |--Site A -- proxies for C\n"
2893 " +--Site A -- proxies for C\n"
2894 " +--Site A -- proxies for C\n"
2895 "Where A = http://127.0.0.1/\n"
2896 " C = http://bar.com/",
2897 DepictFrameTree(root));
2899 // Navigate back to the parent's origin.
2900 url = embedded_test_server()->GetURL("/title1.html");
2901 NavigateFrameToURL(child, url);
2902 EXPECT_EQ(url, observer.last_navigation_url());
2903 EXPECT_TRUE(observer.last_navigation_succeeded());
2904 EXPECT_EQ(
2905 " Site A\n"
2906 " |--Site A\n"
2907 " +--Site A\n"
2908 " |--Site A\n"
2909 " +--Site A\n"
2910 " +--Site A\n"
2911 "Where A = http://127.0.0.1/",
2912 DepictFrameTree(root));
2915 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OpenPopupWithRemoteParent) {
2916 GURL main_url(
2917 embedded_test_server()->GetURL("a.com", "/site_per_process_main.html"));
2918 NavigateToURL(shell(), main_url);
2920 // It is safe to obtain the root frame tree node here, as it doesn't change.
2921 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2922 ->GetFrameTree()
2923 ->root();
2925 // Navigate first child cross-site.
2926 GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
2927 NavigateFrameToURL(root->child_at(0), frame_url);
2929 // Open a popup from the first child.
2930 Shell* new_shell = OpenPopup(root->child_at(0)->current_frame_host(),
2931 GURL(url::kAboutBlankURL), "");
2932 EXPECT_TRUE(new_shell);
2934 // Check that the popup's opener is correct on both the browser and renderer
2935 // sides.
2936 FrameTreeNode* popup_root =
2937 static_cast<WebContentsImpl*>(new_shell->web_contents())
2938 ->GetFrameTree()
2939 ->root();
2940 EXPECT_EQ(root->child_at(0), popup_root->opener());
2942 std::string opener_url;
2943 EXPECT_TRUE(ExecuteScriptAndExtractString(
2944 popup_root->current_frame_host(),
2945 "window.domAutomationController.send(window.opener.location.href);",
2946 &opener_url));
2947 EXPECT_EQ(frame_url.spec(), opener_url);
2949 // Now try the same with a cross-site popup and make sure it ends up in a new
2950 // process and with a correct opener.
2951 GURL popup_url(embedded_test_server()->GetURL("c.com", "/title2.html"));
2952 Shell* cross_site_popup =
2953 OpenPopup(root->child_at(0)->current_frame_host(), popup_url, "");
2954 EXPECT_TRUE(cross_site_popup);
2956 FrameTreeNode* cross_site_popup_root =
2957 static_cast<WebContentsImpl*>(cross_site_popup->web_contents())
2958 ->GetFrameTree()
2959 ->root();
2960 EXPECT_EQ(cross_site_popup_root->current_url(), popup_url);
2962 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
2963 cross_site_popup->web_contents()->GetSiteInstance());
2964 EXPECT_NE(root->child_at(0)->current_frame_host()->GetSiteInstance(),
2965 cross_site_popup->web_contents()->GetSiteInstance());
2967 EXPECT_EQ(root->child_at(0), cross_site_popup_root->opener());
2969 // Ensure the popup's window.opener points to the right subframe. Note that
2970 // we can't check the opener's location as above since it's cross-origin.
2971 bool success = false;
2972 EXPECT_TRUE(ExecuteScriptAndExtractBool(
2973 cross_site_popup_root->current_frame_host(),
2974 "window.domAutomationController.send("
2975 " window.opener === window.opener.top.frames[0]);",
2976 &success));
2977 EXPECT_TRUE(success);
2980 // Verify that named frames are discoverable from their opener's ancestors.
2981 // See https://crbug.com/511474.
2982 // Disable this flaky test on the official cros-trunk for now.
2983 // See crbug.com/515302.
2984 #if defined(OFFICIAL_BUILD)
2985 #define MAYBE_DiscoverNamedFrameFromAncestorOfOpener \
2986 DISABLED_DiscoverNamedFrameFromAncestorOfOpener
2987 #else
2988 #define MAYBE_DiscoverNamedFrameFromAncestorOfOpener \
2989 DiscoverNamedFrameFromAncestorOfOpener
2990 #endif // defined(OFFICIAL_BUILD)
2991 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2992 MAYBE_DiscoverNamedFrameFromAncestorOfOpener) {
2993 GURL main_url(
2994 embedded_test_server()->GetURL("a.com", "/site_per_process_main.html"));
2995 NavigateToURL(shell(), main_url);
2997 // It is safe to obtain the root frame tree node here, as it doesn't change.
2998 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2999 ->GetFrameTree()
3000 ->root();
3002 // Navigate first child cross-site.
3003 GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
3004 NavigateFrameToURL(root->child_at(0), frame_url);
3006 // Open a popup named "foo" from the first child.
3007 Shell* foo_shell = OpenPopup(root->child_at(0)->current_frame_host(),
3008 GURL(url::kAboutBlankURL), "foo");
3009 EXPECT_TRUE(foo_shell);
3011 // Check that a proxy was created for the "foo" popup in a.com.
3012 FrameTreeNode* foo_root =
3013 static_cast<WebContentsImpl*>(foo_shell->web_contents())
3014 ->GetFrameTree()
3015 ->root();
3016 SiteInstance* site_instance_a = root->current_frame_host()->GetSiteInstance();
3017 RenderFrameProxyHost* popup_rfph_for_a =
3018 foo_root->render_manager()->GetRenderFrameProxyHost(site_instance_a);
3019 EXPECT_TRUE(popup_rfph_for_a);
3021 // Verify that the main frame can find the "foo" popup by name. If
3022 // window.open targets the correct frame, the "foo" popup's current URL
3023 // should be updated to |named_frame_url|.
3024 GURL named_frame_url(embedded_test_server()->GetURL("c.com", "/title2.html"));
3025 NavigateNamedFrame(shell()->web_contents(), named_frame_url, "foo");
3026 EXPECT_TRUE(WaitForLoadStop(foo_shell->web_contents()));
3027 EXPECT_EQ(named_frame_url, foo_root->current_url());
3029 // Navigate the popup cross-site and ensure it's still reachable via
3030 // window.open from the main frame.
3031 GURL d_url(embedded_test_server()->GetURL("d.com", "/title3.html"));
3032 NavigateToURL(foo_shell, d_url);
3033 EXPECT_EQ(d_url, foo_root->current_url());
3034 NavigateNamedFrame(shell()->web_contents(), named_frame_url, "foo");
3035 EXPECT_TRUE(WaitForLoadStop(foo_shell->web_contents()));
3036 EXPECT_EQ(named_frame_url, foo_root->current_url());
3039 // Similar to DiscoverNamedFrameFromAncestorOfOpener, but check that if a
3040 // window is created without a name and acquires window.name later, it will
3041 // still be discoverable from its opener's ancestors. Also, instead of using
3042 // an opener's ancestor, this test uses a popup with same origin as that
3043 // ancestor. See https://crbug.com/511474.
3044 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
3045 DiscoverFrameAfterSettingWindowName) {
3046 GURL main_url(
3047 embedded_test_server()->GetURL("a.com", "/site_per_process_main.html"));
3048 NavigateToURL(shell(), main_url);
3050 // It is safe to obtain the root frame tree node here, as it doesn't change.
3051 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
3052 ->GetFrameTree()
3053 ->root();
3055 // Open a same-site popup from the main frame.
3056 GURL a_com_url(embedded_test_server()->GetURL("a.com", "/title3.html"));
3057 Shell* a_com_shell =
3058 OpenPopup(root->child_at(0)->current_frame_host(), a_com_url, "");
3059 EXPECT_TRUE(a_com_shell);
3061 // Navigate first child on main frame cross-site.
3062 GURL frame_url(embedded_test_server()->GetURL("b.com", "/title1.html"));
3063 NavigateFrameToURL(root->child_at(0), frame_url);
3065 // Open an unnamed popup from the first child frame.
3066 Shell* foo_shell = OpenPopup(root->child_at(0)->current_frame_host(),
3067 GURL(url::kAboutBlankURL), "");
3068 EXPECT_TRUE(foo_shell);
3070 // There should be no proxy created for the "foo" popup in a.com, since
3071 // there's no way for the two a.com frames to access it yet.
3072 FrameTreeNode* foo_root =
3073 static_cast<WebContentsImpl*>(foo_shell->web_contents())
3074 ->GetFrameTree()
3075 ->root();
3076 SiteInstance* site_instance_a = root->current_frame_host()->GetSiteInstance();
3077 EXPECT_FALSE(
3078 foo_root->render_manager()->GetRenderFrameProxyHost(site_instance_a));
3080 // Set window.name in the popup's frame.
3081 EXPECT_TRUE(ExecuteScript(foo_shell->web_contents(), "window.name = 'foo'"));
3083 // A proxy for the popup should now exist in a.com.
3084 EXPECT_TRUE(
3085 foo_root->render_manager()->GetRenderFrameProxyHost(site_instance_a));
3087 // Verify that the a.com popup can now find the "foo" popup by name.
3088 GURL named_frame_url(embedded_test_server()->GetURL("c.com", "/title2.html"));
3089 NavigateNamedFrame(a_com_shell->web_contents(), named_frame_url, "foo");
3090 EXPECT_TRUE(WaitForLoadStop(foo_shell->web_contents()));
3091 EXPECT_EQ(named_frame_url, foo_root->current_url());
3094 // Check that frame opener updates work with subframes. Set up a window with a
3095 // popup and update openers for the popup's main frame and subframe to
3096 // subframes on first window, as follows:
3098 // foo +---- bar
3099 // / \ | / \ .
3100 // bar foo <-+ bar foo
3101 // ^ |
3102 // +--------------------+
3104 // The sites are carefully set up so that both opener updates are cross-process
3105 // but still allowed by Blink's navigation checks.
3106 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, UpdateSubframeOpener) {
3107 GURL main_url = embedded_test_server()->GetURL(
3108 "foo.com", "/frame_tree/page_with_two_frames.html");
3109 EXPECT_TRUE(NavigateToURL(shell(), main_url));
3111 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
3112 ->GetFrameTree()
3113 ->root();
3114 EXPECT_EQ(2U, root->child_count());
3116 // From the top frame, open a popup and navigate it to a cross-site page with
3117 // two subframes.
3118 Shell* popup_shell =
3119 OpenPopup(shell()->web_contents(), GURL(url::kAboutBlankURL), "popup");
3120 EXPECT_TRUE(popup_shell);
3121 GURL popup_url(embedded_test_server()->GetURL(
3122 "bar.com", "/frame_tree/page_with_post_message_frames.html"));
3123 NavigateToURL(popup_shell, popup_url);
3125 FrameTreeNode* popup_root =
3126 static_cast<WebContentsImpl*>(popup_shell->web_contents())
3127 ->GetFrameTree()
3128 ->root();
3129 EXPECT_EQ(2U, popup_root->child_count());
3131 // Popup's opener should point to main frame to start with.
3132 EXPECT_EQ(root, popup_root->opener());
3134 // Update the popup's opener to the second subframe on the main page (which
3135 // is same-origin with the top frame, i.e., foo.com).
3136 bool success = false;
3137 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3138 root->child_at(1)->current_frame_host(),
3139 "window.domAutomationController.send(!!window.open('','popup'));",
3140 &success));
3141 EXPECT_TRUE(success);
3143 // Check that updated opener propagated to the browser process and the
3144 // popup's bar.com process.
3145 EXPECT_EQ(root->child_at(1), popup_root->opener());
3147 success = false;
3148 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3149 popup_shell->web_contents(),
3150 "window.domAutomationController.send("
3151 " window.opener === window.opener.parent.frames['frame2']);",
3152 &success));
3153 EXPECT_TRUE(success);
3155 // Now update opener on the popup's second subframe (foo.com) to the main
3156 // page's first subframe (bar.com).
3157 success = false;
3158 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3159 root->child_at(0)->current_frame_host(),
3160 "window.domAutomationController.send(!!window.open('','subframe2'));",
3161 &success));
3162 EXPECT_TRUE(success);
3164 // Check that updated opener propagated to the browser process and the
3165 // foo.com process.
3166 EXPECT_EQ(root->child_at(0), popup_root->child_at(1)->opener());
3168 success = false;
3169 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3170 popup_root->child_at(1)->current_frame_host(),
3171 "window.domAutomationController.send("
3172 " window.opener === window.opener.parent.frames['frame1']);",
3173 &success));
3174 EXPECT_TRUE(success);
3177 // Check that when a subframe navigates to a new SiteInstance, the new
3178 // SiteInstance will get a proxy for the opener of subframe's parent. I.e.,
3179 // accessing parent.opener from the subframe should still work after a
3180 // cross-process navigation.
3181 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
3182 NavigatingSubframePreservesOpenerInParent) {
3183 GURL main_url = embedded_test_server()->GetURL("a.com", "/post_message.html");
3184 EXPECT_TRUE(NavigateToURL(shell(), main_url));
3186 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
3187 ->GetFrameTree()
3188 ->root();
3190 // Open a popup with a cross-site page that has a subframe.
3191 GURL popup_url(embedded_test_server()->GetURL(
3192 "b.com", "/cross_site_iframe_factory.html?b(b)"));
3193 Shell* popup_shell = OpenPopup(shell()->web_contents(), popup_url, "popup");
3194 EXPECT_TRUE(popup_shell);
3195 FrameTreeNode* popup_root =
3196 static_cast<WebContentsImpl*>(popup_shell->web_contents())
3197 ->GetFrameTree()
3198 ->root();
3199 EXPECT_EQ(1U, popup_root->child_count());
3201 // Check that the popup's opener is correct in the browser process.
3202 EXPECT_EQ(root, popup_root->opener());
3204 // Navigate popup's subframe to another site.
3205 GURL frame_url(embedded_test_server()->GetURL("c.com", "/post_message.html"));
3206 NavigateFrameToURL(popup_root->child_at(0), frame_url);
3207 EXPECT_TRUE(
3208 WaitForRenderFrameReady(popup_root->child_at(0)->current_frame_host()));
3210 // Check that the new subframe process still sees correct opener for its
3211 // parent by sending a postMessage to subframe's parent.opener.
3212 bool success = false;
3213 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3214 popup_root->child_at(0)->current_frame_host(),
3215 "window.domAutomationController.send(!!parent.opener);", &success));
3216 EXPECT_TRUE(success);
3218 base::string16 expected_title = base::ASCIIToUTF16("msg");
3219 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
3220 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3221 popup_root->child_at(0)->current_frame_host(),
3222 "window.domAutomationController.send(postToOpenerOfParent('msg','*'));",
3223 &success));
3224 EXPECT_TRUE(success);
3225 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
3228 // Check that if a subframe has an opener, that opener is preserved when the
3229 // subframe navigates cross-site.
3230 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, NavigateSubframeWithOpener) {
3231 GURL main_url(embedded_test_server()->GetURL(
3232 "foo.com", "/frame_tree/page_with_two_frames.html"));
3233 EXPECT_TRUE(NavigateToURL(shell(), main_url));
3235 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
3236 ->GetFrameTree()
3237 ->root();
3238 EXPECT_EQ(
3239 " Site A ------------ proxies for B\n"
3240 " |--Site B ------- proxies for A\n"
3241 " +--Site A ------- proxies for B\n"
3242 "Where A = http://foo.com/\n"
3243 " B = http://bar.com/",
3244 DepictFrameTree(root));
3246 // Update the first (cross-site) subframe's opener to root frame.
3247 bool success = false;
3248 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3249 root->current_frame_host(),
3250 "window.domAutomationController.send(!!window.open('','frame1'));",
3251 &success));
3252 EXPECT_TRUE(success);
3254 // Check that updated opener propagated to the browser process and subframe's
3255 // process.
3256 EXPECT_EQ(root, root->child_at(0)->opener());
3258 success = false;
3259 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3260 root->child_at(0)->current_frame_host(),
3261 "window.domAutomationController.send(window.opener === window.parent);",
3262 &success));
3263 EXPECT_TRUE(success);
3265 // Navigate the subframe with opener to another site.
3266 GURL frame_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
3267 NavigateFrameToURL(root->child_at(0), frame_url);
3269 // Check that the subframe still sees correct opener in its new process.
3270 success = false;
3271 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3272 root->child_at(0)->current_frame_host(),
3273 "window.domAutomationController.send(window.opener === window.parent);",
3274 &success));
3275 EXPECT_TRUE(success);
3277 // Navigate second subframe to a new site. Check that the proxy that's
3278 // created for the first subframe in the new SiteInstance has correct opener.
3279 GURL frame2_url(embedded_test_server()->GetURL("qux.com", "/title1.html"));
3280 NavigateFrameToURL(root->child_at(1), frame2_url);
3282 success = false;
3283 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3284 root->child_at(1)->current_frame_host(),
3285 "window.domAutomationController.send("
3286 " parent.frames['frame1'].opener === parent);",
3287 &success));
3288 EXPECT_TRUE(success);
3291 // Check that if a subframe has an opener, that opener is preserved when a new
3292 // RenderFrameProxy is created for that subframe in another renderer process.
3293 // Similar to NavigateSubframeWithOpener, but this test verifies the subframe
3294 // opener plumbing for FrameMsg_NewFrameProxy, whereas
3295 // NavigateSubframeWithOpener targets FrameMsg_NewFrame.
3296 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
3297 NewRenderFrameProxyPreservesOpener) {
3298 GURL main_url(
3299 embedded_test_server()->GetURL("foo.com", "/post_message.html"));
3300 EXPECT_TRUE(NavigateToURL(shell(), main_url));
3302 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
3303 ->GetFrameTree()
3304 ->root();
3306 // Open a popup with a cross-site page that has two subframes.
3307 GURL popup_url(embedded_test_server()->GetURL(
3308 "bar.com", "/frame_tree/page_with_post_message_frames.html"));
3309 Shell* popup_shell = OpenPopup(shell()->web_contents(), popup_url, "popup");
3310 EXPECT_TRUE(popup_shell);
3311 FrameTreeNode* popup_root =
3312 static_cast<WebContentsImpl*>(popup_shell->web_contents())
3313 ->GetFrameTree()
3314 ->root();
3315 EXPECT_EQ(
3316 " Site A ------------ proxies for B\n"
3317 " |--Site A ------- proxies for B\n"
3318 " +--Site B ------- proxies for A\n"
3319 "Where A = http://bar.com/\n"
3320 " B = http://foo.com/",
3321 DepictFrameTree(popup_root));
3323 // Update the popup's second subframe's opener to root frame. This is
3324 // allowed because that subframe is in the same foo.com SiteInstance as the
3325 // root frame.
3326 bool success = false;
3327 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3328 root->current_frame_host(),
3329 "window.domAutomationController.send(!!window.open('','subframe2'));",
3330 &success));
3331 EXPECT_TRUE(success);
3333 // Check that the opener update propagated to the browser process and bar.com
3334 // process.
3335 EXPECT_EQ(root, popup_root->child_at(1)->opener());
3336 success = false;
3337 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3338 popup_root->child_at(0)->current_frame_host(),
3339 "window.domAutomationController.send("
3340 " parent.frames['subframe2'].opener && "
3341 " parent.frames['subframe2'].opener === parent.opener);",
3342 &success));
3343 EXPECT_TRUE(success);
3345 // Navigate the popup's first subframe to another site.
3346 GURL frame_url(
3347 embedded_test_server()->GetURL("baz.com", "/post_message.html"));
3348 NavigateFrameToURL(popup_root->child_at(0), frame_url);
3349 EXPECT_TRUE(
3350 WaitForRenderFrameReady(popup_root->child_at(0)->current_frame_host()));
3352 // Check that the second subframe's opener is still correct in the first
3353 // subframe's new process. Verify it both in JS and with a postMessage.
3354 success = false;
3355 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3356 popup_root->child_at(0)->current_frame_host(),
3357 "window.domAutomationController.send("
3358 " parent.frames['subframe2'].opener && "
3359 " parent.frames['subframe2'].opener === parent.opener);",
3360 &success));
3361 EXPECT_TRUE(success);
3363 base::string16 expected_title = base::ASCIIToUTF16("msg");
3364 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
3365 EXPECT_TRUE(ExecuteScriptAndExtractBool(
3366 popup_root->child_at(0)->current_frame_host(),
3367 "window.domAutomationController.send("
3368 " postToOpenerOfSibling('subframe2', 'msg', '*'));",
3369 &success));
3370 EXPECT_TRUE(success);
3371 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
3374 } // namespace content