[Session restore] Rename group name Enabled to Restore.
[chromium-blink-merge.git] / content / browser / site_per_process_browsertest.cc
blob4cabf06ff38db27c3579a311ee1438226b37dab0
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 "base/command_line.h"
8 #include "base/strings/stringprintf.h"
9 #include "base/strings/utf_string_conversions.h"
10 #include "content/browser/frame_host/cross_process_frame_connector.h"
11 #include "content/browser/frame_host/frame_tree.h"
12 #include "content/browser/frame_host/navigator.h"
13 #include "content/browser/frame_host/render_frame_proxy_host.h"
14 #include "content/browser/frame_host/render_widget_host_view_child_frame.h"
15 #include "content/browser/renderer_host/render_view_host_impl.h"
16 #include "content/browser/web_contents/web_contents_impl.h"
17 #include "content/public/browser/notification_observer.h"
18 #include "content/public/browser/notification_service.h"
19 #include "content/public/browser/notification_types.h"
20 #include "content/public/common/content_switches.h"
21 #include "content/public/test/browser_test_utils.h"
22 #include "content/public/test/content_browser_test_utils.h"
23 #include "content/public/test/test_navigation_observer.h"
24 #include "content/public/test/test_utils.h"
25 #include "content/shell/browser/shell.h"
26 #include "content/test/content_browser_test_utils_internal.h"
27 #include "content/test/test_frame_navigation_observer.h"
28 #include "net/dns/mock_host_resolver.h"
29 #include "net/test/embedded_test_server/embedded_test_server.h"
31 namespace content {
33 class RedirectNotificationObserver : public NotificationObserver {
34 public:
35 // Register to listen for notifications of the given type from either a
36 // specific source, or from all sources if |source| is
37 // NotificationService::AllSources().
38 RedirectNotificationObserver(int notification_type,
39 const NotificationSource& source);
40 ~RedirectNotificationObserver() override;
42 // Wait until the specified notification occurs. If the notification was
43 // emitted between the construction of this object and this call then it
44 // returns immediately.
45 void Wait();
47 // Returns NotificationService::AllSources() if we haven't observed a
48 // notification yet.
49 const NotificationSource& source() const {
50 return source_;
53 const NotificationDetails& details() const {
54 return details_;
57 // NotificationObserver:
58 void Observe(int type,
59 const NotificationSource& source,
60 const NotificationDetails& details) override;
62 private:
63 bool seen_;
64 bool seen_twice_;
65 bool running_;
66 NotificationRegistrar registrar_;
68 NotificationSource source_;
69 NotificationDetails details_;
70 scoped_refptr<MessageLoopRunner> message_loop_runner_;
72 DISALLOW_COPY_AND_ASSIGN(RedirectNotificationObserver);
75 RedirectNotificationObserver::RedirectNotificationObserver(
76 int notification_type,
77 const NotificationSource& source)
78 : seen_(false),
79 running_(false),
80 source_(NotificationService::AllSources()) {
81 registrar_.Add(this, notification_type, source);
84 RedirectNotificationObserver::~RedirectNotificationObserver() {}
86 void RedirectNotificationObserver::Wait() {
87 if (seen_ && seen_twice_)
88 return;
90 running_ = true;
91 message_loop_runner_ = new MessageLoopRunner;
92 message_loop_runner_->Run();
93 EXPECT_TRUE(seen_);
96 void RedirectNotificationObserver::Observe(
97 int type,
98 const NotificationSource& source,
99 const NotificationDetails& details) {
100 source_ = source;
101 details_ = details;
102 seen_twice_ = seen_;
103 seen_ = true;
104 if (!running_)
105 return;
107 message_loop_runner_->Quit();
108 running_ = false;
111 // This observer keeps track of the number of created RenderFrameHosts. Tests
112 // can use this to ensure that a certain number of child frames has been
113 // created after navigating.
114 class RenderFrameHostCreatedObserver : public WebContentsObserver {
115 public:
116 RenderFrameHostCreatedObserver(WebContents* web_contents,
117 int expected_frame_count)
118 : WebContentsObserver(web_contents),
119 expected_frame_count_(expected_frame_count),
120 frames_created_(0),
121 message_loop_runner_(new MessageLoopRunner) {}
123 ~RenderFrameHostCreatedObserver() override;
125 // Runs a nested message loop and blocks until the expected number of
126 // RenderFrameHosts is created.
127 void Wait();
129 private:
130 // WebContentsObserver
131 void RenderFrameCreated(RenderFrameHost* render_frame_host) override;
133 // The number of RenderFrameHosts to wait for.
134 int expected_frame_count_;
136 // The number of RenderFrameHosts that have been created.
137 int frames_created_;
139 // The MessageLoopRunner used to spin the message loop.
140 scoped_refptr<MessageLoopRunner> message_loop_runner_;
142 DISALLOW_COPY_AND_ASSIGN(RenderFrameHostCreatedObserver);
145 RenderFrameHostCreatedObserver::~RenderFrameHostCreatedObserver() {
148 void RenderFrameHostCreatedObserver::Wait() {
149 message_loop_runner_->Run();
152 void RenderFrameHostCreatedObserver::RenderFrameCreated(
153 RenderFrameHost* render_frame_host) {
154 frames_created_++;
155 if (frames_created_ == expected_frame_count_) {
156 message_loop_runner_->Quit();
161 // SitePerProcessBrowserTest
164 SitePerProcessBrowserTest::SitePerProcessBrowserTest() {
167 void SitePerProcessBrowserTest::StartFrameAtDataURL() {
168 std::string data_url_script =
169 "var iframes = document.getElementById('test');iframes.src="
170 "'data:text/html,dataurl';";
171 ASSERT_TRUE(ExecuteScript(shell()->web_contents(), data_url_script));
174 void SitePerProcessBrowserTest::SetUpCommandLine(
175 base::CommandLine* command_line) {
176 command_line->AppendSwitch(switches::kSitePerProcess);
179 void SitePerProcessBrowserTest::SetUpOnMainThread() {
180 host_resolver()->AddRule("*", "127.0.0.1");
181 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
182 SetupCrossSiteRedirector(embedded_test_server());
185 // Ensure that navigating subframes in --site-per-process mode works and the
186 // correct documents are committed.
187 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframe) {
188 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
189 NavigateToURL(shell(), main_url);
191 // It is safe to obtain the root frame tree node here, as it doesn't change.
192 FrameTreeNode* root =
193 static_cast<WebContentsImpl*>(shell()->web_contents())->
194 GetFrameTree()->root();
196 TestNavigationObserver observer(shell()->web_contents());
198 // Load same-site page into iframe.
199 FrameTreeNode* child = root->child_at(0);
200 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
201 NavigateFrameToURL(child, http_url);
202 EXPECT_EQ(http_url, observer.last_navigation_url());
203 EXPECT_TRUE(observer.last_navigation_succeeded());
205 // There should be only one RenderWidgetHost when there are no
206 // cross-process iframes.
207 std::set<RenderWidgetHostView*> views_set =
208 static_cast<WebContentsImpl*>(shell()->web_contents())
209 ->GetRenderWidgetHostViewsInTree();
210 EXPECT_EQ(1U, views_set.size());
212 RenderFrameProxyHost* proxy_to_parent =
213 child->render_manager()->GetRenderFrameProxyHost(
214 shell()->web_contents()->GetSiteInstance());
215 EXPECT_FALSE(proxy_to_parent);
217 // Load cross-site page into iframe.
218 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
219 NavigateFrameToURL(root->child_at(0), url);
220 // Verify that the navigation succeeded and the expected URL was loaded.
221 EXPECT_TRUE(observer.last_navigation_succeeded());
222 EXPECT_EQ(url, observer.last_navigation_url());
224 // Ensure that we have created a new process for the subframe.
225 ASSERT_EQ(2U, root->child_count());
226 SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
227 RenderViewHost* rvh = child->current_frame_host()->render_view_host();
228 RenderProcessHost* rph = child->current_frame_host()->GetProcess();
229 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh);
230 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
231 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), rph);
233 // There should be now two RenderWidgetHosts, one for each process
234 // rendering a frame.
235 std::set<RenderWidgetHostView*> views_set =
236 static_cast<WebContentsImpl*>(shell()->web_contents())
237 ->GetRenderWidgetHostViewsInTree();
238 EXPECT_EQ(2U, views_set.size());
240 proxy_to_parent = child->render_manager()->GetProxyToParent();
241 EXPECT_TRUE(proxy_to_parent);
242 EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
243 // The out-of-process iframe should have its own RenderWidgetHost,
244 // independent of any RenderViewHost.
245 EXPECT_NE(
246 rvh->GetView(),
247 proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
248 EXPECT_TRUE(child->current_frame_host()->GetRenderWidgetHost());
250 // Load another cross-site page into the same iframe.
251 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
252 NavigateFrameToURL(root->child_at(0), url);
253 EXPECT_TRUE(observer.last_navigation_succeeded());
254 EXPECT_EQ(url, observer.last_navigation_url());
256 // Check again that a new process is created and is different from the
257 // top level one and the previous one.
258 ASSERT_EQ(2U, root->child_count());
259 child = root->child_at(0);
260 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(),
261 child->current_frame_host()->render_view_host());
262 EXPECT_NE(rvh, child->current_frame_host()->render_view_host());
263 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
264 child->current_frame_host()->GetSiteInstance());
265 EXPECT_NE(site_instance,
266 child->current_frame_host()->GetSiteInstance());
267 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(),
268 child->current_frame_host()->GetProcess());
269 EXPECT_NE(rph, child->current_frame_host()->GetProcess());
271 std::set<RenderWidgetHostView*> views_set =
272 static_cast<WebContentsImpl*>(shell()->web_contents())
273 ->GetRenderWidgetHostViewsInTree();
274 EXPECT_EQ(2U, views_set.size());
276 EXPECT_EQ(proxy_to_parent, child->render_manager()->GetProxyToParent());
277 EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
278 EXPECT_NE(
279 child->current_frame_host()->render_view_host()->GetView(),
280 proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
281 EXPECT_TRUE(child->current_frame_host()->GetRenderWidgetHost());
284 // Tests OOPIF rendering by checking that the RWH of the iframe generates
285 // OnSwapCompositorFrame message.
286 #if defined(OS_ANDROID)
287 // http://crbug.com/471850
288 #define MAYBE_CompositorFrameSwapped DISABLED_CompositorFrameSwapped
289 #else
290 #define MAYBE_CompositorFrameSwapped CompositorFrameSwapped
291 #endif
292 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
293 MAYBE_CompositorFrameSwapped) {
294 GURL main_url(
295 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
296 NavigateToURL(shell(), main_url);
298 // It is safe to obtain the root frame tree node here, as it doesn't change.
299 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
300 ->GetFrameTree()
301 ->root();
302 ASSERT_EQ(1U, root->child_count());
304 FrameTreeNode* child_node = root->child_at(0);
305 GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
306 EXPECT_EQ(site_url, child_node->current_url());
307 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
308 child_node->current_frame_host()->GetSiteInstance());
309 RenderWidgetHostViewBase* rwhv_base = static_cast<RenderWidgetHostViewBase*>(
310 child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
312 // Wait for OnSwapCompositorFrame message.
313 while (rwhv_base->RendererFrameNumber() <= 0) {
314 // TODO(lazyboy): Find a better way to avoid sleeping like this. See
315 // http://crbug.com/405282 for details.
316 base::RunLoop run_loop;
317 base::MessageLoop::current()->PostDelayedTask(
318 FROM_HERE, run_loop.QuitClosure(),
319 base::TimeDelta::FromMilliseconds(10));
320 run_loop.Run();
324 // Disabled for flaky crashing: crbug.com/446575
325 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
326 NavigateRemoteFrame) {
327 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
328 NavigateToURL(shell(), main_url);
330 // It is safe to obtain the root frame tree node here, as it doesn't change.
331 FrameTreeNode* root =
332 static_cast<WebContentsImpl*>(shell()->web_contents())->
333 GetFrameTree()->root();
335 TestNavigationObserver observer(shell()->web_contents());
337 // Load same-site page into iframe.
338 FrameTreeNode* child = root->child_at(0);
339 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
340 NavigateFrameToURL(child, http_url);
341 EXPECT_EQ(http_url, observer.last_navigation_url());
342 EXPECT_TRUE(observer.last_navigation_succeeded());
344 // Load cross-site page into iframe.
345 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
346 NavigateFrameToURL(root->child_at(0), url);
347 EXPECT_TRUE(observer.last_navigation_succeeded());
348 EXPECT_EQ(url, observer.last_navigation_url());
350 // Ensure that we have created a new process for the subframe.
351 ASSERT_EQ(2U, root->child_count());
352 SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
353 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
355 // Emulate the main frame changing the src of the iframe such that it
356 // navigates cross-site.
357 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
358 NavigateIframeToURL(shell()->web_contents(), "test", url);
359 EXPECT_TRUE(observer.last_navigation_succeeded());
360 EXPECT_EQ(url, observer.last_navigation_url());
362 // Check again that a new process is created and is different from the
363 // top level one and the previous one.
364 ASSERT_EQ(2U, root->child_count());
365 child = root->child_at(0);
366 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
367 child->current_frame_host()->GetSiteInstance());
368 EXPECT_NE(site_instance,
369 child->current_frame_host()->GetSiteInstance());
371 // Navigate back to the parent's origin and ensure we return to the
372 // parent's process.
373 NavigateFrameToURL(child, http_url);
374 EXPECT_EQ(http_url, observer.last_navigation_url());
375 EXPECT_TRUE(observer.last_navigation_succeeded());
376 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
377 child->current_frame_host()->GetSiteInstance());
380 #if defined(OS_WIN)
381 // http://crbug.com/446575
382 #define MAYBE_NavigateRemoteFrameToBlankAndDataURLs \
383 DISABLED_NavigateRemoteFrameToBlankAndDataURLs
384 #else
385 #define MAYBE_NavigateRemoteFrameToBlankAndDataURLs \
386 NavigateRemoteFrameToBlankAndDataURLs
387 #endif
389 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
390 MAYBE_NavigateRemoteFrameToBlankAndDataURLs) {
391 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
392 NavigateToURL(shell(), main_url);
394 // It is safe to obtain the root frame tree node here, as it doesn't change.
395 FrameTreeNode* root =
396 static_cast<WebContentsImpl*>(shell()->web_contents())->
397 GetFrameTree()->root();
399 TestNavigationObserver observer(shell()->web_contents());
401 // Load same-site page into iframe.
402 FrameTreeNode* child = root->child_at(0);
403 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
404 NavigateFrameToURL(child, http_url);
405 EXPECT_EQ(http_url, observer.last_navigation_url());
406 EXPECT_TRUE(observer.last_navigation_succeeded());
408 // Load cross-site page into iframe.
409 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
410 NavigateFrameToURL(root->child_at(0), url);
411 EXPECT_TRUE(observer.last_navigation_succeeded());
412 EXPECT_EQ(url, observer.last_navigation_url());
413 ASSERT_EQ(2U, root->child_count());
414 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
415 root->child_at(0)->current_frame_host()->GetSiteInstance());
417 // Navigate iframe to a data URL. The navigation happens from a script in the
418 // parent frame, so the data URL should be committed in the same SiteInstance
419 // as the parent frame.
420 GURL data_url("data:text/html,dataurl");
421 NavigateIframeToURL(shell()->web_contents(), "test", data_url);
422 EXPECT_TRUE(observer.last_navigation_succeeded());
423 EXPECT_EQ(data_url, observer.last_navigation_url());
425 // Ensure that we have navigated using the top level process.
426 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
427 root->child_at(0)->current_frame_host()->GetSiteInstance());
429 // Load cross-site page into iframe.
430 url = embedded_test_server()->GetURL("bar.com", "/title2.html");
431 NavigateFrameToURL(root->child_at(0), url);
432 EXPECT_TRUE(observer.last_navigation_succeeded());
433 EXPECT_EQ(url, observer.last_navigation_url());
434 ASSERT_EQ(2U, root->child_count());
435 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
436 root->child_at(0)->current_frame_host()->GetSiteInstance());
438 // Navigate iframe to about:blank. The navigation happens from a script in the
439 // parent frame, so it should be committed in the same SiteInstance as the
440 // parent frame.
441 GURL about_blank_url("about:blank");
442 NavigateIframeToURL(shell()->web_contents(), "test", about_blank_url);
443 EXPECT_TRUE(observer.last_navigation_succeeded());
444 EXPECT_EQ(about_blank_url, observer.last_navigation_url());
446 // Ensure that we have navigated using the top level process.
447 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
448 root->child_at(0)->current_frame_host()->GetSiteInstance());
451 // This test checks that killing a renderer process of a remote frame
452 // and then navigating some other frame to the same SiteInstance of the killed
453 // process works properly.
454 // This can be illustrated as follows,
455 // where 1/2/3 are FrameTreeNode-s and A/B are processes and B* is the killed
456 // B process:
458 // 1 A A A
459 // / \ -> / \ -> Kill B -> / \ -> Navigate 3 to B -> / \ .
460 // 2 3 B A B* A B* B
462 // Initially, node1.proxy_hosts_ = {B}
463 // After we kill B, we make sure B stays in node1.proxy_hosts_, then we navigate
464 // 3 to B and we expect that to complete normally.
465 // See http://crbug.com/432107.
467 // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
468 // site B and stays in not rendered state.
469 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
470 NavigateRemoteFrameToKilledProcess) {
471 GURL main_url(embedded_test_server()->GetURL(
472 "/frame_tree/page_with_two_frames.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 =
477 static_cast<WebContentsImpl*>(shell()->web_contents())->
478 GetFrameTree()->root();
480 TestNavigationObserver observer(shell()->web_contents());
481 ASSERT_EQ(2U, root->child_count());
483 // Make sure node2 points to the correct cross-site page.
484 GURL site_b_url = embedded_test_server()->GetURL("bar.com", "/title1.html");
485 FrameTreeNode* node2 = root->child_at(0);
486 EXPECT_EQ(site_b_url, node2->current_url());
488 // Kill that cross-site renderer.
489 RenderProcessHost* child_process =
490 node2->current_frame_host()->GetProcess();
491 RenderProcessHostWatcher crash_observer(
492 child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
493 child_process->Shutdown(0, false);
494 crash_observer.Wait();
496 // Now navigate the second iframe (node3) to the same site as the node2.
497 FrameTreeNode* node3 = root->child_at(1);
498 NavigateFrameToURL(node3, site_b_url);
499 EXPECT_TRUE(observer.last_navigation_succeeded());
500 EXPECT_EQ(site_b_url, observer.last_navigation_url());
503 // This test is similar to
504 // SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcess with
505 // addition that node2 also has a cross-origin frame to site C.
507 // 1 A A A
508 // / \ / \ / \ / \ .
509 // 2 3 -> B A -> Kill B -> B* A -> Navigate 3 -> B* B
510 // / /
511 // 4 C
513 // Initially, node1.proxy_hosts_ = {B, C}
514 // After we kill B, we make sure B stays in node1.proxy_hosts_, but
515 // C gets cleared from node1.proxy_hosts_.
517 // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
518 // site B and stays in not rendered state.
519 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
520 NavigateRemoteFrameToKilledProcessWithSubtree) {
521 GURL main_url(
522 embedded_test_server()->GetURL(
523 "/frame_tree/page_with_two_frames_nested.html"));
524 NavigateToURL(shell(), main_url);
526 // It is safe to obtain the root frame tree node here, as it doesn't change.
527 FrameTreeNode* root =
528 static_cast<WebContentsImpl*>(shell()->web_contents())->
529 GetFrameTree()->root();
530 TestNavigationObserver observer(shell()->web_contents());
532 ASSERT_EQ(2U, root->child_count());
534 GURL site_b_url(
535 embedded_test_server()->GetURL(
536 "bar.com", "/frame_tree/page_with_one_frame.html"));
537 // We can't use a TestNavigationObserver to verify the URL here,
538 // since the frame has children that may have clobbered it in the observer.
539 EXPECT_EQ(site_b_url, root->child_at(0)->current_url());
541 // Ensure that a new process is created for node2.
542 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
543 root->child_at(0)->current_frame_host()->GetSiteInstance());
544 // Ensure that a new process is *not* created for node3.
545 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
546 root->child_at(1)->current_frame_host()->GetSiteInstance());
548 ASSERT_EQ(1U, root->child_at(0)->child_count());
550 // Make sure node4 points to the correct cross-site page.
551 FrameTreeNode* node4 = root->child_at(0)->child_at(0);
552 GURL site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
553 EXPECT_EQ(site_c_url, node4->current_url());
555 // |site_instance_c| is expected to go away once we kill |child_process_b|
556 // below, so create a local scope so we can extend the lifetime of
557 // |site_instance_c| with a refptr.
559 SiteInstance* site_instance_b =
560 root->child_at(0)->current_frame_host()->GetSiteInstance();
561 // |site_c| will go away, so extend its lifetime with a refptr.
562 scoped_refptr<SiteInstanceImpl> site_instance_c =
563 node4->current_frame_host()->GetSiteInstance();
565 // Initially proxies for both B and C will be present in the root and node3.
566 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(
567 site_instance_b));
568 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(
569 site_instance_c.get()));
570 FrameTreeNode* node3 = root->child_at(1);
571 EXPECT_TRUE(node3->render_manager()->GetRenderFrameProxyHost(
572 site_instance_b));
573 EXPECT_TRUE(node3->render_manager()->GetRenderFrameProxyHost(
574 site_instance_c.get()));
576 // Kill that cross-site renderer/process B.
577 RenderProcessHost* child_process_b =
578 root->child_at(0)->current_frame_host()->GetProcess();
579 RenderProcessHostWatcher crash_observer(
580 child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
581 child_process_b->Shutdown(0, false);
582 crash_observer.Wait();
584 // Make sure proxy B stays around in root and node3.
585 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(
586 site_instance_b));
587 EXPECT_TRUE(node3->render_manager()->GetRenderFrameProxyHost(
588 site_instance_b));
589 // Make sure proxy C goes away from root and node3.
590 EXPECT_FALSE(root->render_manager()->GetRenderFrameProxyHost(
591 site_instance_c.get()));
592 EXPECT_FALSE(node3->render_manager()->GetRenderFrameProxyHost(
593 site_instance_c.get()));
596 // Now navigate the second iframe (node3) to the same site as the node2.
597 FrameTreeNode* node3 = root->child_at(1);
598 GURL url = embedded_test_server()->GetURL("bar.com", "/title1.html");
599 NavigateFrameToURL(node3, url);
600 EXPECT_TRUE(observer.last_navigation_succeeded());
601 EXPECT_EQ(url, observer.last_navigation_url());
604 // In A-embed-B-embed-C scenario, verify that killing process B clears proxies
605 // of C from the tree.
607 // 1 A A
608 // / \ / \ / \ .
609 // 2 3 -> B A -> Kill B -> B* A
610 // / /
611 // 4 C
613 // node1 is the root.
614 // Initially, both node1.proxy_hosts_ and node3.proxy_hosts_ contain C.
615 // After we kill B, make sure proxies for C are cleared.
616 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
617 KillingRendererClearsDescendantProxies) {
618 GURL main_url(
619 embedded_test_server()->GetURL(
620 "/frame_tree/page_with_two_frames_nested.html"));
621 NavigateToURL(shell(), main_url);
623 // It is safe to obtain the root frame tree node here, as it doesn't change.
624 FrameTreeNode* root =
625 static_cast<WebContentsImpl*>(shell()->web_contents())->
626 GetFrameTree()->root();
627 TestNavigationObserver observer(shell()->web_contents());
629 ASSERT_EQ(2U, root->child_count());
631 GURL site_b_url(
632 embedded_test_server()->GetURL(
633 "bar.com", "/frame_tree/page_with_one_frame.html"));
634 // We can't use a TestNavigationObserver to verify the URL here,
635 // since the frame has children that may have clobbered it in the observer.
636 EXPECT_EQ(site_b_url, root->child_at(0)->current_url());
638 // Ensure that a new process is created for node2.
639 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
640 root->child_at(0)->current_frame_host()->GetSiteInstance());
641 // Ensure that a new process is *not* created for node3.
642 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
643 root->child_at(1)->current_frame_host()->GetSiteInstance());
645 ASSERT_EQ(1U, root->child_at(0)->child_count());
647 // Make sure node4 points to the correct cross-site-page.
648 FrameTreeNode* node4 = root->child_at(0)->child_at(0);
649 GURL site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
650 EXPECT_EQ(site_c_url, node4->current_url());
652 // |site_instance_c| is expected to go away once we kill |child_process_b|
653 // below, so create a local scope so we can extend the lifetime of
654 // |site_instance_c| with a refptr.
656 SiteInstance* site_instance_b =
657 root->child_at(0)->current_frame_host()->GetSiteInstance();
658 scoped_refptr<SiteInstanceImpl> site_instance_c =
659 node4->current_frame_host()->GetSiteInstance();
661 // Initially proxies for both B and C will be present in the root.
662 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(
663 site_instance_b));
664 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(
665 site_instance_c.get()));
667 // Kill process B.
668 RenderProcessHost* child_process_b =
669 root->child_at(0)->current_frame_host()->GetProcess();
670 RenderProcessHostWatcher crash_observer(
671 child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
672 child_process_b->Shutdown(0, false);
673 crash_observer.Wait();
675 // Make sure proxy C has gone from root.
676 EXPECT_FALSE(root->render_manager()->GetRenderFrameProxyHost(
677 site_instance_c.get()));
678 // Make sure proxy C has gone from node3 as well.
679 EXPECT_FALSE(root->child_at(1)->render_manager()->GetRenderFrameProxyHost(
680 site_instance_c.get()));
681 // Make sure proxy B stays around in root and node3.
682 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(
683 site_instance_b));
684 EXPECT_TRUE(root->child_at(1)->render_manager()->GetRenderFrameProxyHost(
685 site_instance_b));
689 // Crash a subframe and ensures its children are cleared from the FrameTree.
690 // See http://crbug.com/338508.
691 // TODO(creis): Disabled for flakiness; see http://crbug.com/405582.
692 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DISABLED_CrashSubframe) {
693 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
694 NavigateToURL(shell(), main_url);
696 StartFrameAtDataURL();
698 // These must stay in scope with replace_host.
699 GURL::Replacements replace_host;
700 std::string foo_com("foo.com");
702 // Load cross-site page into iframe.
703 EXPECT_TRUE(NavigateIframeToURL(
704 shell()->web_contents(), "test",
705 embedded_test_server()->GetURL("/cross-site/foo.com/title2.html")));
707 // Check the subframe process.
708 FrameTreeNode* root =
709 static_cast<WebContentsImpl*>(shell()->web_contents())->
710 GetFrameTree()->root();
711 ASSERT_EQ(2U, root->child_count());
712 FrameTreeNode* child = root->child_at(0);
713 EXPECT_EQ(main_url, root->current_url());
714 EXPECT_EQ("foo.com", child->current_url().host());
715 EXPECT_EQ("/title2.html", child->current_url().path());
717 EXPECT_TRUE(
718 child->current_frame_host()->render_view_host()->IsRenderViewLive());
719 EXPECT_TRUE(child->current_frame_host()->IsRenderFrameLive());
721 // Crash the subframe process.
722 RenderProcessHost* root_process = root->current_frame_host()->GetProcess();
723 RenderProcessHost* child_process = child->current_frame_host()->GetProcess();
725 RenderProcessHostWatcher crash_observer(
726 child_process,
727 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
728 child_process->Shutdown(0, false);
729 crash_observer.Wait();
732 // Ensure that the child frame still exists but has been cleared.
733 EXPECT_EQ(2U, root->child_count());
734 EXPECT_EQ(main_url, root->current_url());
735 EXPECT_EQ(GURL(), child->current_url());
737 EXPECT_FALSE(
738 child->current_frame_host()->render_view_host()->IsRenderViewLive());
739 EXPECT_FALSE(child->current_frame_host()->IsRenderFrameLive());
740 EXPECT_FALSE(child->current_frame_host()->render_frame_created_);
742 // Now crash the top-level page to clear the child frame.
744 RenderProcessHostWatcher crash_observer(
745 root_process,
746 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
747 root_process->Shutdown(0, false);
748 crash_observer.Wait();
750 EXPECT_EQ(0U, root->child_count());
751 EXPECT_EQ(GURL(), root->current_url());
754 // When a new subframe is added, related SiteInstances that can reach the
755 // subframe should create proxies for it (https://crbug.com/423587). This test
756 // checks that if A embeds B and later adds a new subframe A2, A2 gets a proxy
757 // in B's process.
758 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CreateProxiesForNewFrames) {
759 GURL main_url(
760 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
761 EXPECT_TRUE(NavigateToURL(shell(), main_url));
763 // It is safe to obtain the root frame tree node here, as it doesn't change.
764 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
765 ->GetFrameTree()
766 ->root();
767 ASSERT_EQ(1U, root->child_count());
769 // Make sure the frame starts out at the correct cross-site URL.
770 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"),
771 root->child_at(0)->current_url());
773 // Add a new child frame to the top-level frame.
774 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 1);
775 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
776 "window.domAutomationController.send("
777 " addFrame('data:text/html,foo'));"));
778 frame_observer.Wait();
779 ASSERT_EQ(2U, root->child_count());
781 // The new child frame should now have a proxy in first frame's process.
782 RenderFrameProxyHost* proxy =
783 root->child_at(1)->render_manager()->GetRenderFrameProxyHost(
784 root->child_at(0)->current_frame_host()->GetSiteInstance());
785 EXPECT_TRUE(proxy);
788 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
789 // security checks are back in place.
790 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
791 // on Android (http://crbug.com/187570).
792 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
793 DISABLED_CrossSiteIframeRedirectOnce) {
794 ASSERT_TRUE(test_server()->Start());
795 net::SpawnedTestServer https_server(
796 net::SpawnedTestServer::TYPE_HTTPS,
797 net::SpawnedTestServer::kLocalhost,
798 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
799 ASSERT_TRUE(https_server.Start());
801 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
802 GURL http_url(test_server()->GetURL("files/title1.html"));
803 GURL https_url(https_server.GetURL("files/title1.html"));
805 NavigateToURL(shell(), main_url);
807 TestNavigationObserver observer(shell()->web_contents());
809 // Load cross-site client-redirect page into Iframe.
810 // Should be blocked.
811 GURL client_redirect_https_url(https_server.GetURL(
812 "client-redirect?files/title1.html"));
813 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
814 client_redirect_https_url));
815 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
816 EXPECT_EQ(observer.last_navigation_url(), client_redirect_https_url);
817 EXPECT_FALSE(observer.last_navigation_succeeded());
821 // Load cross-site server-redirect page into Iframe,
822 // which redirects to same-site page.
823 GURL server_redirect_http_url(https_server.GetURL(
824 "server-redirect?" + http_url.spec()));
825 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
826 server_redirect_http_url));
827 EXPECT_EQ(observer.last_navigation_url(), http_url);
828 EXPECT_TRUE(observer.last_navigation_succeeded());
832 // Load cross-site server-redirect page into Iframe,
833 // which redirects to cross-site page.
834 GURL server_redirect_http_url(https_server.GetURL(
835 "server-redirect?files/title1.html"));
836 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
837 server_redirect_http_url));
838 // DidFailProvisionalLoad when navigating to https_url.
839 EXPECT_EQ(observer.last_navigation_url(), https_url);
840 EXPECT_FALSE(observer.last_navigation_succeeded());
844 // Load same-site server-redirect page into Iframe,
845 // which redirects to cross-site page.
846 GURL server_redirect_http_url(test_server()->GetURL(
847 "server-redirect?" + https_url.spec()));
848 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
849 server_redirect_http_url));
851 EXPECT_EQ(observer.last_navigation_url(), https_url);
852 EXPECT_FALSE(observer.last_navigation_succeeded());
856 // Load same-site client-redirect page into Iframe,
857 // which redirects to cross-site page.
858 GURL client_redirect_http_url(test_server()->GetURL(
859 "client-redirect?" + https_url.spec()));
861 RedirectNotificationObserver load_observer2(
862 NOTIFICATION_LOAD_STOP,
863 Source<NavigationController>(
864 &shell()->web_contents()->GetController()));
866 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
867 client_redirect_http_url));
869 // Same-site Client-Redirect Page should be loaded successfully.
870 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
871 EXPECT_TRUE(observer.last_navigation_succeeded());
873 // Redirecting to Cross-site Page should be blocked.
874 load_observer2.Wait();
875 EXPECT_EQ(observer.last_navigation_url(), https_url);
876 EXPECT_FALSE(observer.last_navigation_succeeded());
880 // Load same-site server-redirect page into Iframe,
881 // which redirects to same-site page.
882 GURL server_redirect_http_url(test_server()->GetURL(
883 "server-redirect?files/title1.html"));
884 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
885 server_redirect_http_url));
886 EXPECT_EQ(observer.last_navigation_url(), http_url);
887 EXPECT_TRUE(observer.last_navigation_succeeded());
891 // Load same-site client-redirect page into Iframe,
892 // which redirects to same-site page.
893 GURL client_redirect_http_url(test_server()->GetURL(
894 "client-redirect?" + http_url.spec()));
895 RedirectNotificationObserver load_observer2(
896 NOTIFICATION_LOAD_STOP,
897 Source<NavigationController>(
898 &shell()->web_contents()->GetController()));
900 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
901 client_redirect_http_url));
903 // Same-site Client-Redirect Page should be loaded successfully.
904 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
905 EXPECT_TRUE(observer.last_navigation_succeeded());
907 // Redirecting to Same-site Page should be loaded successfully.
908 load_observer2.Wait();
909 EXPECT_EQ(observer.last_navigation_url(), http_url);
910 EXPECT_TRUE(observer.last_navigation_succeeded());
914 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
915 // security checks are back in place.
916 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
917 // on Android (http://crbug.com/187570).
918 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
919 DISABLED_CrossSiteIframeRedirectTwice) {
920 ASSERT_TRUE(test_server()->Start());
921 net::SpawnedTestServer https_server(
922 net::SpawnedTestServer::TYPE_HTTPS,
923 net::SpawnedTestServer::kLocalhost,
924 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
925 ASSERT_TRUE(https_server.Start());
927 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
928 GURL http_url(test_server()->GetURL("files/title1.html"));
929 GURL https_url(https_server.GetURL("files/title1.html"));
931 NavigateToURL(shell(), main_url);
933 TestNavigationObserver observer(shell()->web_contents());
935 // Load client-redirect page pointing to a cross-site client-redirect page,
936 // which eventually redirects back to same-site page.
937 GURL client_redirect_https_url(https_server.GetURL(
938 "client-redirect?" + http_url.spec()));
939 GURL client_redirect_http_url(test_server()->GetURL(
940 "client-redirect?" + client_redirect_https_url.spec()));
942 // We should wait until second client redirect get cancelled.
943 RedirectNotificationObserver load_observer2(
944 NOTIFICATION_LOAD_STOP,
945 Source<NavigationController>(
946 &shell()->web_contents()->GetController()));
948 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
949 client_redirect_http_url));
951 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
952 load_observer2.Wait();
953 EXPECT_EQ(observer.last_navigation_url(), client_redirect_https_url);
954 EXPECT_FALSE(observer.last_navigation_succeeded());
958 // Load server-redirect page pointing to a cross-site server-redirect page,
959 // which eventually redirect back to same-site page.
960 GURL server_redirect_https_url(https_server.GetURL(
961 "server-redirect?" + http_url.spec()));
962 GURL server_redirect_http_url(test_server()->GetURL(
963 "server-redirect?" + server_redirect_https_url.spec()));
964 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
965 server_redirect_http_url));
966 EXPECT_EQ(observer.last_navigation_url(), http_url);
967 EXPECT_TRUE(observer.last_navigation_succeeded());
971 // Load server-redirect page pointing to a cross-site server-redirect page,
972 // which eventually redirects back to cross-site page.
973 GURL server_redirect_https_url(https_server.GetURL(
974 "server-redirect?" + https_url.spec()));
975 GURL server_redirect_http_url(test_server()->GetURL(
976 "server-redirect?" + server_redirect_https_url.spec()));
977 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
978 server_redirect_http_url));
980 // DidFailProvisionalLoad when navigating to https_url.
981 EXPECT_EQ(observer.last_navigation_url(), https_url);
982 EXPECT_FALSE(observer.last_navigation_succeeded());
986 // Load server-redirect page pointing to a cross-site client-redirect page,
987 // which eventually redirects back to same-site page.
988 GURL client_redirect_http_url(https_server.GetURL(
989 "client-redirect?" + http_url.spec()));
990 GURL server_redirect_http_url(test_server()->GetURL(
991 "server-redirect?" + client_redirect_http_url.spec()));
992 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
993 server_redirect_http_url));
995 // DidFailProvisionalLoad when navigating to client_redirect_http_url.
996 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
997 EXPECT_FALSE(observer.last_navigation_succeeded());
1001 // Ensure that when navigating a frame cross-process RenderFrameProxyHosts are
1002 // created in the FrameTree skipping the subtree of the navigating frame.
1004 // Disabled on Mac due to flakiness on ASAN. http://crbug.com/425248
1005 // Disabled on Windows due to flakiness on Win 7 bot. http://crbug.com/444563
1006 #if defined(OS_MACOSX) || defined(OS_WIN)
1007 #define MAYBE_ProxyCreationSkipsSubtree DISABLED_ProxyCreationSkipsSubtree
1008 #else
1009 #define MAYBE_ProxyCreationSkipsSubtree ProxyCreationSkipsSubtree
1010 #endif
1011 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1012 MAYBE_ProxyCreationSkipsSubtree) {
1013 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1014 NavigateToURL(shell(), main_url);
1016 // It is safe to obtain the root frame tree node here, as it doesn't change.
1017 FrameTreeNode* root =
1018 static_cast<WebContentsImpl*>(shell()->web_contents())->
1019 GetFrameTree()->root();
1021 EXPECT_TRUE(root->child_at(1) != NULL);
1022 EXPECT_EQ(2U, root->child_at(1)->child_count());
1025 // Load same-site page into iframe.
1026 TestNavigationObserver observer(shell()->web_contents());
1027 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
1028 NavigateFrameToURL(root->child_at(0), http_url);
1029 EXPECT_EQ(http_url, observer.last_navigation_url());
1030 EXPECT_TRUE(observer.last_navigation_succeeded());
1031 RenderFrameProxyHost* proxy_to_parent =
1032 root->child_at(0)->render_manager()->GetRenderFrameProxyHost(
1033 shell()->web_contents()->GetSiteInstance());
1034 EXPECT_FALSE(proxy_to_parent);
1037 // Create the cross-site URL to navigate to.
1038 GURL cross_site_url =
1039 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html");
1041 // Load cross-site page into the second iframe without waiting for the
1042 // navigation to complete. Once LoadURLWithParams returns, we would expect
1043 // proxies to have been created in the frame tree, but children of the
1044 // navigating frame to still be present. The reason is that we don't run the
1045 // message loop, so no IPCs that alter the frame tree can be processed.
1046 FrameTreeNode* child = root->child_at(1);
1047 SiteInstance* site = NULL;
1049 TestNavigationObserver observer(shell()->web_contents());
1050 TestFrameNavigationObserver navigation_observer(child);
1051 NavigationController::LoadURLParams params(cross_site_url);
1052 params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
1053 params.frame_tree_node_id = child->frame_tree_node_id();
1054 child->navigator()->GetController()->LoadURLWithParams(params);
1055 EXPECT_TRUE(child->render_manager()->pending_frame_host());
1057 site = child->render_manager()->pending_frame_host()->GetSiteInstance();
1058 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site);
1060 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(site));
1061 EXPECT_TRUE(
1062 root->child_at(0)->render_manager()->GetRenderFrameProxyHost(site));
1063 EXPECT_FALSE(child->render_manager()->GetRenderFrameProxyHost(site));
1064 for (size_t i = 0; i < child->child_count(); ++i) {
1065 EXPECT_FALSE(
1066 child->child_at(i)->render_manager()->GetRenderFrameProxyHost(site));
1068 // Now that the verification is done, run the message loop and wait for the
1069 // navigation to complete.
1070 navigation_observer.Wait();
1071 EXPECT_FALSE(child->render_manager()->pending_frame_host());
1072 EXPECT_TRUE(observer.last_navigation_succeeded());
1073 EXPECT_EQ(cross_site_url, observer.last_navigation_url());
1076 // Load another cross-site page into the same iframe.
1077 cross_site_url = embedded_test_server()->GetURL("bar.com", "/title2.html");
1079 // Perform the same checks as the first cross-site navigation, since
1080 // there have been issues in subsequent cross-site navigations. Also ensure
1081 // that the SiteInstance has properly changed.
1082 // TODO(nasko): Once we have proper cleanup of resources, add code to
1083 // verify that the intermediate SiteInstance/RenderFrameHost have been
1084 // properly cleaned up.
1085 TestNavigationObserver observer(shell()->web_contents());
1086 TestFrameNavigationObserver navigation_observer(child);
1087 NavigationController::LoadURLParams params(cross_site_url);
1088 params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
1089 params.frame_tree_node_id = child->frame_tree_node_id();
1090 child->navigator()->GetController()->LoadURLWithParams(params);
1091 EXPECT_TRUE(child->render_manager()->pending_frame_host() != NULL);
1093 SiteInstance* site2 =
1094 child->render_manager()->pending_frame_host()->GetSiteInstance();
1095 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site2);
1096 EXPECT_NE(site, site2);
1098 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(site2));
1099 EXPECT_TRUE(
1100 root->child_at(0)->render_manager()->GetRenderFrameProxyHost(site2));
1101 EXPECT_FALSE(child->render_manager()->GetRenderFrameProxyHost(site2));
1102 for (size_t i = 0; i < child->child_count(); ++i) {
1103 EXPECT_FALSE(
1104 child->child_at(i)->render_manager()->GetRenderFrameProxyHost(site2));
1107 navigation_observer.Wait();
1108 EXPECT_TRUE(observer.last_navigation_succeeded());
1109 EXPECT_EQ(cross_site_url, observer.last_navigation_url());
1110 EXPECT_EQ(0U, child->child_count());
1114 // Verify that origin replication works for an A-embed-B-embed-C hierarchy.
1115 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OriginReplication) {
1116 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1117 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1119 // It is safe to obtain the root frame tree node here, as it doesn't change.
1120 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1121 ->GetFrameTree()
1122 ->root();
1124 TestNavigationObserver observer(shell()->web_contents());
1126 // Navigate the first subframe to a cross-site page with two subframes.
1127 // NavigateFrameToURL can't be used here because it doesn't guarantee that
1128 // FrameTreeNodes will have been created for child frames when it returns.
1129 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 4);
1130 GURL foo_url(
1131 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
1132 NavigationController::LoadURLParams params(foo_url);
1133 params.transition_type = ui::PAGE_TRANSITION_LINK;
1134 params.frame_tree_node_id = root->child_at(0)->frame_tree_node_id();
1135 root->child_at(0)->navigator()->GetController()->LoadURLWithParams(params);
1136 frame_observer.Wait();
1138 // We can't use a TestNavigationObserver to verify the URL here,
1139 // since the frame has children that may have clobbered it in the observer.
1140 EXPECT_EQ(foo_url, root->child_at(0)->current_url());
1142 // Ensure that a new process is created for the subframe.
1143 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1144 root->child_at(0)->current_frame_host()->GetSiteInstance());
1146 // Load cross-site page into subframe's subframe.
1147 ASSERT_EQ(2U, root->child_at(0)->child_count());
1148 GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
1149 NavigateFrameToURL(root->child_at(0)->child_at(0), bar_url);
1150 EXPECT_TRUE(observer.last_navigation_succeeded());
1151 EXPECT_EQ(bar_url, observer.last_navigation_url());
1153 // Check that a new process is created and is different from the top one and
1154 // the middle one.
1155 FrameTreeNode* bottom_child = root->child_at(0)->child_at(0);
1156 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1157 bottom_child->current_frame_host()->GetSiteInstance());
1158 EXPECT_NE(root->child_at(0)->current_frame_host()->GetSiteInstance(),
1159 bottom_child->current_frame_host()->GetSiteInstance());
1161 // Check that foo.com frame's location.ancestorOrigins contains the correct
1162 // origin for the parent. The origin should have been replicated as part of
1163 // the ViewMsg_New message that created the parent's RenderFrameProxy in
1164 // foo.com's process.
1165 int ancestor_origins_length = 0;
1166 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1167 root->child_at(0)->current_frame_host(),
1168 "window.domAutomationController.send(location.ancestorOrigins.length);",
1169 &ancestor_origins_length));
1170 EXPECT_EQ(1, ancestor_origins_length);
1171 std::string result;
1172 EXPECT_TRUE(ExecuteScriptAndExtractString(
1173 root->child_at(0)->current_frame_host(),
1174 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1175 &result));
1176 EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
1178 // Check that bar.com frame's location.ancestorOrigins contains the correct
1179 // origin for its two ancestors. The topmost parent origin should be
1180 // replicated as part of ViewMsg_New, and the middle frame (foo.com's) origin
1181 // should be replicated as part of FrameMsg_NewFrameProxy sent for foo.com's
1182 // frame in bar.com's process.
1183 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1184 bottom_child->current_frame_host(),
1185 "window.domAutomationController.send(location.ancestorOrigins.length);",
1186 &ancestor_origins_length));
1187 EXPECT_EQ(2, ancestor_origins_length);
1188 EXPECT_TRUE(ExecuteScriptAndExtractString(
1189 bottom_child->current_frame_host(),
1190 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1191 &result));
1192 EXPECT_EQ(result + "/", foo_url.GetOrigin().spec());
1193 EXPECT_TRUE(ExecuteScriptAndExtractString(
1194 bottom_child->current_frame_host(),
1195 "window.domAutomationController.send(location.ancestorOrigins[1]);",
1196 &result));
1197 EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
1200 // Check that iframe sandbox flags are replicated correctly.
1201 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SandboxFlagsReplication) {
1202 GURL main_url(embedded_test_server()->GetURL("/sandboxed_frames.html"));
1203 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1205 // It is safe to obtain the root frame tree node here, as it doesn't change.
1206 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1207 ->GetFrameTree()
1208 ->root();
1210 TestNavigationObserver observer(shell()->web_contents());
1212 // Navigate the second (sandboxed) subframe to a cross-site page with a
1213 // subframe. Use RenderFrameHostCreatedObserver to guarantee that all
1214 // FrameTreeNodes are created for child frames.
1215 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 4);
1216 GURL foo_url(
1217 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
1218 NavigateFrameToURL(root->child_at(1), foo_url);
1219 frame_observer.Wait();
1221 // We can't use a TestNavigationObserver to verify the URL here,
1222 // since the frame has children that may have clobbered it in the observer.
1223 EXPECT_EQ(foo_url, root->child_at(1)->current_url());
1225 // Load cross-site page into subframe's subframe.
1226 ASSERT_EQ(2U, root->child_at(1)->child_count());
1227 GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
1228 NavigateFrameToURL(root->child_at(1)->child_at(0), bar_url);
1229 EXPECT_TRUE(observer.last_navigation_succeeded());
1230 EXPECT_EQ(bar_url, observer.last_navigation_url());
1232 // Opening a popup in the sandboxed foo.com iframe should fail.
1233 bool success = false;
1234 EXPECT_TRUE(
1235 ExecuteScriptAndExtractBool(root->child_at(1)->current_frame_host(),
1236 "window.domAutomationController.send("
1237 "!window.open('data:text/html,dataurl'));",
1238 &success));
1239 EXPECT_TRUE(success);
1240 EXPECT_EQ(1u, Shell::windows().size());
1242 // Opening a popup in a frame whose parent is sandboxed should also fail.
1243 // Here, bar.com frame's sandboxed parent frame is a remote frame in
1244 // bar.com's process.
1245 success = false;
1246 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1247 root->child_at(1)->child_at(0)->current_frame_host(),
1248 "window.domAutomationController.send("
1249 "!window.open('data:text/html,dataurl'));",
1250 &success));
1251 EXPECT_TRUE(success);
1252 EXPECT_EQ(1u, Shell::windows().size());
1254 // Same, but now try the case where bar.com frame's sandboxed parent is a
1255 // local frame in bar.com's process.
1256 success = false;
1257 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1258 root->child_at(2)->child_at(0)->current_frame_host(),
1259 "window.domAutomationController.send("
1260 "!window.open('data:text/html,dataurl'));",
1261 &success));
1262 EXPECT_TRUE(success);
1263 EXPECT_EQ(1u, Shell::windows().size());
1265 // Check that foo.com frame's location.ancestorOrigins contains the correct
1266 // origin for the parent, which should be unaffected by sandboxing.
1267 int ancestor_origins_length = 0;
1268 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1269 root->child_at(1)->current_frame_host(),
1270 "window.domAutomationController.send(location.ancestorOrigins.length);",
1271 &ancestor_origins_length));
1272 EXPECT_EQ(1, ancestor_origins_length);
1273 std::string result;
1274 EXPECT_TRUE(ExecuteScriptAndExtractString(
1275 root->child_at(1)->current_frame_host(),
1276 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1277 &result));
1278 EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
1280 // Now check location.ancestorOrigins for the bar.com frame. The middle frame
1281 // (foo.com's) origin should be unique, since that frame is sandboxed, and
1282 // the top frame should match |main_url|.
1283 FrameTreeNode* bottom_child = root->child_at(1)->child_at(0);
1284 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1285 bottom_child->current_frame_host(),
1286 "window.domAutomationController.send(location.ancestorOrigins.length);",
1287 &ancestor_origins_length));
1288 EXPECT_EQ(2, ancestor_origins_length);
1289 EXPECT_TRUE(ExecuteScriptAndExtractString(
1290 bottom_child->current_frame_host(),
1291 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1292 &result));
1293 EXPECT_EQ("null", result);
1294 EXPECT_TRUE(ExecuteScriptAndExtractString(
1295 bottom_child->current_frame_host(),
1296 "window.domAutomationController.send(location.ancestorOrigins[1]);",
1297 &result));
1298 EXPECT_EQ(main_url.GetOrigin().spec(), result + "/");
1301 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
1302 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicSandboxFlags) {
1303 GURL main_url(
1304 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
1305 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1307 // It is safe to obtain the root frame tree node here, as it doesn't change.
1308 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1309 ->GetFrameTree()
1310 ->root();
1312 TestNavigationObserver observer(shell()->web_contents());
1313 ASSERT_EQ(2U, root->child_count());
1315 // Make sure first frame starts out at the correct cross-site page.
1316 EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"),
1317 root->child_at(0)->current_url());
1319 // Navigate second frame to another cross-site page.
1320 GURL baz_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
1321 NavigateFrameToURL(root->child_at(1), baz_url);
1322 EXPECT_TRUE(observer.last_navigation_succeeded());
1323 EXPECT_EQ(baz_url, observer.last_navigation_url());
1325 // Both frames should not be sandboxed to start with.
1326 EXPECT_EQ(SandboxFlags::NONE,
1327 root->child_at(0)->current_replication_state().sandbox_flags);
1328 EXPECT_EQ(SandboxFlags::NONE, root->child_at(0)->effective_sandbox_flags());
1329 EXPECT_EQ(SandboxFlags::NONE,
1330 root->child_at(1)->current_replication_state().sandbox_flags);
1331 EXPECT_EQ(SandboxFlags::NONE, root->child_at(1)->effective_sandbox_flags());
1333 // Dynamically update sandbox flags for the first frame.
1334 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1335 "window.domAutomationController.send("
1336 "document.querySelector('iframe').sandbox="
1337 "'allow-scripts');"));
1339 // Check that updated sandbox flags are propagated to browser process.
1340 // The new flags should be set in current_replication_state(), while
1341 // effective_sandbox_flags() should still reflect the old flags, because
1342 // sandbox flag updates take place only after navigations. "allow-scripts"
1343 // resets both SandboxFlags::Scripts and SandboxFlags::AutomaticFeatures bits
1344 // per blink::parseSandboxPolicy().
1345 SandboxFlags expected_flags = SandboxFlags::ALL & ~SandboxFlags::SCRIPTS &
1346 ~SandboxFlags::AUTOMATIC_FEATURES;
1347 EXPECT_EQ(expected_flags,
1348 root->child_at(0)->current_replication_state().sandbox_flags);
1349 EXPECT_EQ(SandboxFlags::NONE, root->child_at(0)->effective_sandbox_flags());
1351 // Navigate the first frame to a page on the same site. The new sandbox
1352 // flags should take effect. The new page has a child frame, so use
1353 // TestFrameNavigationObserver to wait for it to be loaded.
1354 TestFrameNavigationObserver frame_observer(root->child_at(0), 2);
1355 GURL bar_url(
1356 embedded_test_server()->GetURL("bar.com", "/frame_tree/2-4.html"));
1357 NavigateFrameToURL(root->child_at(0), bar_url);
1358 frame_observer.Wait();
1359 EXPECT_EQ(bar_url, root->child_at(0)->current_url());
1360 ASSERT_EQ(1U, root->child_at(0)->child_count());
1362 // Confirm that the browser process has updated the frame's current sandbox
1363 // flags.
1364 EXPECT_EQ(expected_flags,
1365 root->child_at(0)->current_replication_state().sandbox_flags);
1366 EXPECT_EQ(expected_flags, root->child_at(0)->effective_sandbox_flags());
1368 // Opening a popup in the now-sandboxed frame should fail.
1369 bool success = false;
1370 EXPECT_TRUE(
1371 ExecuteScriptAndExtractBool(root->child_at(0)->current_frame_host(),
1372 "window.domAutomationController.send("
1373 "!window.open('data:text/html,dataurl'));",
1374 &success));
1375 EXPECT_TRUE(success);
1376 EXPECT_EQ(1u, Shell::windows().size());
1378 // Navigate the child of the now-sandboxed frame to a page on baz.com. The
1379 // child should inherit the latest sandbox flags from its parent frame, which
1380 // is currently a proxy in baz.com's renderer process. This checks that the
1381 // proxies of |root->child_at(0)| were also updated with the latest sandbox
1382 // flags.
1383 GURL baz_child_url(embedded_test_server()->GetURL("baz.com", "/title2.html"));
1384 NavigateFrameToURL(root->child_at(0)->child_at(0), baz_child_url);
1385 EXPECT_TRUE(observer.last_navigation_succeeded());
1386 EXPECT_EQ(baz_child_url, observer.last_navigation_url());
1388 // Opening a popup in the child of a sandboxed frame should fail.
1389 success = false;
1390 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1391 root->child_at(0)->child_at(0)->current_frame_host(),
1392 "window.domAutomationController.send("
1393 "!window.open('data:text/html,dataurl'));",
1394 &success));
1395 EXPECT_TRUE(success);
1396 EXPECT_EQ(1u, Shell::windows().size());
1399 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
1400 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1401 DynamicSandboxFlagsRemoteToLocal) {
1402 GURL main_url(
1403 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
1404 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1406 // It is safe to obtain the root frame tree node here, as it doesn't change.
1407 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1408 ->GetFrameTree()
1409 ->root();
1411 TestNavigationObserver observer(shell()->web_contents());
1412 ASSERT_EQ(2U, root->child_count());
1414 // Make sure the two frames starts out at correct URLs.
1415 EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"),
1416 root->child_at(0)->current_url());
1417 EXPECT_EQ(embedded_test_server()->GetURL("/title1.html"),
1418 root->child_at(1)->current_url());
1420 // Update the second frame's sandbox flags.
1421 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1422 "window.domAutomationController.send("
1423 "document.querySelectorAll('iframe')[1].sandbox="
1424 "'allow-scripts');"));
1426 // Check that the current sandbox flags are updated but the effective
1427 // sandbox flags are not.
1428 SandboxFlags expected_flags = SandboxFlags::ALL & ~SandboxFlags::SCRIPTS &
1429 ~SandboxFlags::AUTOMATIC_FEATURES;
1430 EXPECT_EQ(expected_flags,
1431 root->child_at(1)->current_replication_state().sandbox_flags);
1432 EXPECT_EQ(SandboxFlags::NONE, root->child_at(1)->effective_sandbox_flags());
1434 // Navigate the second subframe to a page on bar.com. This will trigger a
1435 // remote-to-local frame swap in bar.com's process. The target page has
1436 // another frame, so use TestFrameNavigationObserver to wait for all frames
1437 // to be loaded.
1438 TestFrameNavigationObserver frame_observer(root->child_at(1), 2);
1439 GURL bar_url(embedded_test_server()->GetURL(
1440 "bar.com", "/frame_tree/page_with_one_frame.html"));
1441 NavigateFrameToURL(root->child_at(1), bar_url);
1442 frame_observer.Wait();
1443 EXPECT_EQ(bar_url, root->child_at(1)->current_url());
1444 ASSERT_EQ(1U, root->child_at(1)->child_count());
1446 // Confirm that the browser process has updated the current sandbox flags.
1447 EXPECT_EQ(expected_flags,
1448 root->child_at(1)->current_replication_state().sandbox_flags);
1449 EXPECT_EQ(expected_flags, root->child_at(1)->effective_sandbox_flags());
1451 // Opening a popup in the sandboxed second frame should fail.
1452 bool success = false;
1453 EXPECT_TRUE(
1454 ExecuteScriptAndExtractBool(root->child_at(1)->current_frame_host(),
1455 "window.domAutomationController.send("
1456 "!window.open('data:text/html,dataurl'));",
1457 &success));
1458 EXPECT_TRUE(success);
1459 EXPECT_EQ(1u, Shell::windows().size());
1461 // Make sure that the child frame inherits the sandbox flags of its
1462 // now-sandboxed parent frame.
1463 success = false;
1464 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1465 root->child_at(1)->child_at(0)->current_frame_host(),
1466 "window.domAutomationController.send("
1467 "!window.open('data:text/html,dataurl'));",
1468 &success));
1469 EXPECT_TRUE(success);
1470 EXPECT_EQ(1u, Shell::windows().size());
1473 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
1474 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1475 DynamicSandboxFlagsRendererInitiatedNavigation) {
1476 GURL main_url(
1477 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
1478 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1480 // It is safe to obtain the root frame tree node here, as it doesn't change.
1481 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1482 ->GetFrameTree()
1483 ->root();
1485 TestNavigationObserver observer(shell()->web_contents());
1486 ASSERT_EQ(1U, root->child_count());
1488 // Make sure the frame starts out at the correct cross-site page.
1489 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"),
1490 root->child_at(0)->current_url());
1492 // The frame should not be sandboxed to start with.
1493 EXPECT_EQ(SandboxFlags::NONE,
1494 root->child_at(0)->current_replication_state().sandbox_flags);
1495 EXPECT_EQ(SandboxFlags::NONE, root->child_at(0)->effective_sandbox_flags());
1497 // Dynamically update the frame's sandbox flags.
1498 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1499 "window.domAutomationController.send("
1500 "document.querySelector('iframe').sandbox="
1501 "'allow-scripts');"));
1503 // Check that updated sandbox flags are propagated to browser process.
1504 // The new flags should be set in current_replication_state(), while
1505 // effective_sandbox_flags() should still reflect the old flags, because
1506 // sandbox flag updates take place only after navigations. "allow-scripts"
1507 // resets both SandboxFlags::Scripts and SandboxFlags::AutomaticFeatures bits
1508 // per blink::parseSandboxPolicy().
1509 SandboxFlags expected_flags = SandboxFlags::ALL & ~SandboxFlags::SCRIPTS &
1510 ~SandboxFlags::AUTOMATIC_FEATURES;
1511 EXPECT_EQ(expected_flags,
1512 root->child_at(0)->current_replication_state().sandbox_flags);
1513 EXPECT_EQ(SandboxFlags::NONE, root->child_at(0)->effective_sandbox_flags());
1515 // Perform a renderer-initiated same-site navigation in the first frame. The
1516 // new sandbox flags should take effect.
1517 TestFrameNavigationObserver frame_observer(root->child_at(0));
1518 ASSERT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
1519 "window.location.href='/title2.html'"));
1520 frame_observer.Wait();
1521 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title2.html"),
1522 root->child_at(0)->current_url());
1524 // Confirm that the browser process has updated the frame's current sandbox
1525 // flags.
1526 EXPECT_EQ(expected_flags,
1527 root->child_at(0)->current_replication_state().sandbox_flags);
1528 EXPECT_EQ(expected_flags, root->child_at(0)->effective_sandbox_flags());
1530 // Opening a popup in the now-sandboxed frame should fail.
1531 bool success = false;
1532 EXPECT_TRUE(
1533 ExecuteScriptAndExtractBool(root->child_at(0)->current_frame_host(),
1534 "window.domAutomationController.send("
1535 "!window.open('data:text/html,dataurl'));",
1536 &success));
1537 EXPECT_TRUE(success);
1538 EXPECT_EQ(1u, Shell::windows().size());
1541 // Verify that a child frame can retrieve the name property set by its parent.
1542 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, WindowNameReplication) {
1543 GURL main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html"));
1544 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1546 // It is safe to obtain the root frame tree node here, as it doesn't change.
1547 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1548 ->GetFrameTree()
1549 ->root();
1551 TestNavigationObserver observer(shell()->web_contents());
1553 // Load cross-site page into iframe.
1554 GURL frame_url =
1555 embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html");
1556 NavigateFrameToURL(root->child_at(0), frame_url);
1557 EXPECT_TRUE(observer.last_navigation_succeeded());
1558 EXPECT_EQ(frame_url, observer.last_navigation_url());
1560 // Ensure that a new process is created for the subframe.
1561 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1562 root->child_at(0)->current_frame_host()->GetSiteInstance());
1564 // Check that the window.name seen by the frame matches the name attribute
1565 // specified by its parent in the iframe tag.
1566 std::string result;
1567 EXPECT_TRUE(ExecuteScriptAndExtractString(
1568 root->child_at(0)->current_frame_host(),
1569 "window.domAutomationController.send(window.name);", &result));
1570 EXPECT_EQ("3-1-name", result);
1573 // Verify that dynamic updates to a frame's window.name propagate to the
1574 // frame's proxies, so that the latest frame names can be used in navigations.
1575 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicWindowName) {
1576 GURL main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html"));
1577 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1579 // It is safe to obtain the root frame tree node here, as it doesn't change.
1580 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1581 ->GetFrameTree()
1582 ->root();
1583 TestNavigationObserver observer(shell()->web_contents());
1585 // Load cross-site page into iframe.
1586 GURL frame_url =
1587 embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html");
1588 NavigateFrameToURL(root->child_at(0), frame_url);
1589 EXPECT_TRUE(observer.last_navigation_succeeded());
1590 EXPECT_EQ(frame_url, observer.last_navigation_url());
1592 // Browser process should know the child frame's original window.name
1593 // specified in the iframe element.
1594 EXPECT_EQ(root->child_at(0)->frame_name(), "3-1-name");
1596 // Update the child frame's window.name.
1597 EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
1598 "window.domAutomationController.send("
1599 "window.name = 'updated-name');"));
1601 // The change should propagate to the browser process.
1602 EXPECT_EQ(root->child_at(0)->frame_name(), "updated-name");
1604 // The proxy in the parent process should also receive the updated name.
1605 // Check that it can reference the child frame by its new name.
1606 bool success = false;
1607 EXPECT_TRUE(
1608 ExecuteScriptAndExtractBool(shell()->web_contents(),
1609 "window.domAutomationController.send("
1610 "frames['updated-name'] == frames[0]);",
1611 &success));
1612 EXPECT_TRUE(success);
1614 // Issue a renderer-initiated navigation from the root frame to the child
1615 // frame using the frame's name. Make sure correct frame is navigated.
1617 // TODO(alexmos): When blink::createWindow is refactored to handle
1618 // RemoteFrames, this should also be tested via window.open(url, frame_name)
1619 // and a more complicated frame hierarchy (https://crbug.com/463742)
1620 TestFrameNavigationObserver frame_observer(root->child_at(0));
1621 GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
1622 std::string script = base::StringPrintf(
1623 "window.domAutomationController.send("
1624 "frames['updated-name'].location.href = '%s');",
1625 foo_url.spec().c_str());
1626 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), script));
1627 frame_observer.Wait();
1628 EXPECT_EQ(foo_url, root->child_at(0)->current_url());
1631 // Ensure that navigating subframes in --site-per-process mode properly fires
1632 // the DidStopLoading event on WebContentsObserver.
1633 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteDidStopLoading) {
1634 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1635 NavigateToURL(shell(), main_url);
1637 // It is safe to obtain the root frame tree node here, as it doesn't change.
1638 FrameTreeNode* root =
1639 static_cast<WebContentsImpl*>(shell()->web_contents())->
1640 GetFrameTree()->root();
1642 TestNavigationObserver observer(shell()->web_contents());
1644 // Load same-site page into iframe.
1645 FrameTreeNode* child = root->child_at(0);
1646 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
1647 NavigateFrameToURL(child, http_url);
1648 EXPECT_EQ(http_url, observer.last_navigation_url());
1649 EXPECT_TRUE(observer.last_navigation_succeeded());
1651 // Load cross-site page into iframe.
1652 TestNavigationObserver nav_observer(shell()->web_contents(), 1);
1653 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
1654 NavigationController::LoadURLParams params(url);
1655 params.transition_type = ui::PAGE_TRANSITION_LINK;
1656 params.frame_tree_node_id = child->frame_tree_node_id();
1657 child->navigator()->GetController()->LoadURLWithParams(params);
1658 nav_observer.Wait();
1660 // Verify that the navigation succeeded and the expected URL was loaded.
1661 EXPECT_TRUE(observer.last_navigation_succeeded());
1662 EXPECT_EQ(url, observer.last_navigation_url());
1665 // Ensure that the renderer does not crash when navigating a frame that has a
1666 // sibling RemoteFrame. See https://crbug.com/426953.
1667 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1668 NavigateWithSiblingRemoteFrame) {
1669 GURL main_url(
1670 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
1671 NavigateToURL(shell(), main_url);
1673 // It is safe to obtain the root frame tree node here, as it doesn't change.
1674 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1675 ->GetFrameTree()
1676 ->root();
1677 TestNavigationObserver observer(shell()->web_contents());
1679 // Make sure the first frame is out of process.
1680 ASSERT_EQ(2U, root->child_count());
1681 FrameTreeNode* node2 = root->child_at(0);
1682 EXPECT_NE(root->current_frame_host()->GetSiteInstance(),
1683 node2->current_frame_host()->GetSiteInstance());
1685 // Make sure the second frame is in the parent's process.
1686 FrameTreeNode* node3 = root->child_at(1);
1687 EXPECT_EQ(root->current_frame_host()->GetSiteInstance(),
1688 node3->current_frame_host()->GetSiteInstance());
1690 // Navigate the second iframe (node3) to a URL in its own process.
1691 GURL title_url = embedded_test_server()->GetURL("/title2.html");
1692 NavigateFrameToURL(node3, title_url);
1693 EXPECT_TRUE(observer.last_navigation_succeeded());
1694 EXPECT_EQ(title_url, observer.last_navigation_url());
1695 EXPECT_EQ(root->current_frame_host()->GetSiteInstance(),
1696 node3->current_frame_host()->GetSiteInstance());
1697 EXPECT_TRUE(node3->current_frame_host()->IsRenderFrameLive());
1700 // Verify that load events for iframe elements work when the child frame is
1701 // out-of-process. In such cases, the load event is forwarded from the child
1702 // frame to the parent frame via the browser process.
1703 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, LoadEventForwarding) {
1704 // Load a page with a cross-site frame. The parent page has an onload
1705 // handler in the iframe element that appends "LOADED" to the document title.
1707 GURL main_url(
1708 embedded_test_server()->GetURL("/frame_with_load_event.html"));
1709 base::string16 expected_title(base::UTF8ToUTF16("LOADED"));
1710 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
1711 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1712 EXPECT_EQ(title_watcher.WaitAndGetTitle(), expected_title);
1715 // It is safe to obtain the root frame tree node here, as it doesn't change.
1716 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1717 ->GetFrameTree()
1718 ->root();
1720 // Load another cross-site page into the iframe and check that the load event
1721 // is fired.
1723 GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
1724 base::string16 expected_title(base::UTF8ToUTF16("LOADEDLOADED"));
1725 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
1726 TestNavigationObserver observer(shell()->web_contents());
1727 NavigateFrameToURL(root->child_at(0), foo_url);
1728 EXPECT_TRUE(observer.last_navigation_succeeded());
1729 EXPECT_EQ(foo_url, observer.last_navigation_url());
1730 EXPECT_EQ(title_watcher.WaitAndGetTitle(), expected_title);
1734 } // namespace content