Supervised user whitelists: Cleanup
[chromium-blink-merge.git] / content / browser / site_per_process_browsertest.cc
blob29ee0e1d0636155cf31a69abee6e9e3a58bad2e4
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "content/browser/site_per_process_browsertest.h"
7 #include <algorithm>
8 #include <vector>
10 #include "base/command_line.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "content/browser/frame_host/cross_process_frame_connector.h"
14 #include "content/browser/frame_host/frame_tree.h"
15 #include "content/browser/frame_host/navigator.h"
16 #include "content/browser/frame_host/render_frame_proxy_host.h"
17 #include "content/browser/frame_host/render_widget_host_view_child_frame.h"
18 #include "content/browser/renderer_host/render_view_host_impl.h"
19 #include "content/browser/web_contents/web_contents_impl.h"
20 #include "content/common/frame_messages.h"
21 #include "content/public/browser/navigation_details.h"
22 #include "content/public/browser/notification_observer.h"
23 #include "content/public/browser/notification_service.h"
24 #include "content/public/browser/notification_types.h"
25 #include "content/public/common/content_switches.h"
26 #include "content/public/test/browser_test_utils.h"
27 #include "content/public/test/content_browser_test_utils.h"
28 #include "content/public/test/test_navigation_observer.h"
29 #include "content/public/test/test_utils.h"
30 #include "content/shell/browser/shell.h"
31 #include "content/test/content_browser_test_utils_internal.h"
32 #include "content/test/test_frame_navigation_observer.h"
33 #include "ipc/ipc_security_test_util.h"
34 #include "net/dns/mock_host_resolver.h"
35 #include "net/test/embedded_test_server/embedded_test_server.h"
37 namespace content {
39 class RedirectNotificationObserver : public NotificationObserver {
40 public:
41 // Register to listen for notifications of the given type from either a
42 // specific source, or from all sources if |source| is
43 // NotificationService::AllSources().
44 RedirectNotificationObserver(int notification_type,
45 const NotificationSource& source);
46 ~RedirectNotificationObserver() override;
48 // Wait until the specified notification occurs. If the notification was
49 // emitted between the construction of this object and this call then it
50 // returns immediately.
51 void Wait();
53 // Returns NotificationService::AllSources() if we haven't observed a
54 // notification yet.
55 const NotificationSource& source() const {
56 return source_;
59 const NotificationDetails& details() const {
60 return details_;
63 // NotificationObserver:
64 void Observe(int type,
65 const NotificationSource& source,
66 const NotificationDetails& details) override;
68 private:
69 bool seen_;
70 bool seen_twice_;
71 bool running_;
72 NotificationRegistrar registrar_;
74 NotificationSource source_;
75 NotificationDetails details_;
76 scoped_refptr<MessageLoopRunner> message_loop_runner_;
78 DISALLOW_COPY_AND_ASSIGN(RedirectNotificationObserver);
81 RedirectNotificationObserver::RedirectNotificationObserver(
82 int notification_type,
83 const NotificationSource& source)
84 : seen_(false),
85 running_(false),
86 source_(NotificationService::AllSources()) {
87 registrar_.Add(this, notification_type, source);
90 RedirectNotificationObserver::~RedirectNotificationObserver() {}
92 void RedirectNotificationObserver::Wait() {
93 if (seen_ && seen_twice_)
94 return;
96 running_ = true;
97 message_loop_runner_ = new MessageLoopRunner;
98 message_loop_runner_->Run();
99 EXPECT_TRUE(seen_);
102 void RedirectNotificationObserver::Observe(
103 int type,
104 const NotificationSource& source,
105 const NotificationDetails& details) {
106 source_ = source;
107 details_ = details;
108 seen_twice_ = seen_;
109 seen_ = true;
110 if (!running_)
111 return;
113 message_loop_runner_->Quit();
114 running_ = false;
117 // This observer keeps track of the number of created RenderFrameHosts. Tests
118 // can use this to ensure that a certain number of child frames has been
119 // created after navigating.
120 class RenderFrameHostCreatedObserver : public WebContentsObserver {
121 public:
122 RenderFrameHostCreatedObserver(WebContents* web_contents,
123 int expected_frame_count)
124 : WebContentsObserver(web_contents),
125 expected_frame_count_(expected_frame_count),
126 frames_created_(0),
127 message_loop_runner_(new MessageLoopRunner) {}
129 ~RenderFrameHostCreatedObserver() override;
131 // Runs a nested message loop and blocks until the expected number of
132 // RenderFrameHosts is created.
133 void Wait();
135 private:
136 // WebContentsObserver
137 void RenderFrameCreated(RenderFrameHost* render_frame_host) override;
139 // The number of RenderFrameHosts to wait for.
140 int expected_frame_count_;
142 // The number of RenderFrameHosts that have been created.
143 int frames_created_;
145 // The MessageLoopRunner used to spin the message loop.
146 scoped_refptr<MessageLoopRunner> message_loop_runner_;
148 DISALLOW_COPY_AND_ASSIGN(RenderFrameHostCreatedObserver);
151 RenderFrameHostCreatedObserver::~RenderFrameHostCreatedObserver() {
154 void RenderFrameHostCreatedObserver::Wait() {
155 message_loop_runner_->Run();
158 void RenderFrameHostCreatedObserver::RenderFrameCreated(
159 RenderFrameHost* render_frame_host) {
160 frames_created_++;
161 if (frames_created_ == expected_frame_count_) {
162 message_loop_runner_->Quit();
167 // SitePerProcessBrowserTest
170 SitePerProcessBrowserTest::SitePerProcessBrowserTest() {
173 std::string SitePerProcessBrowserTest::DepictFrameTree(FrameTreeNode* node) {
174 return visualizer_.DepictFrameTree(node);
177 void SitePerProcessBrowserTest::StartFrameAtDataURL() {
178 std::string data_url_script =
179 "var iframes = document.getElementById('test');iframes.src="
180 "'data:text/html,dataurl';";
181 ASSERT_TRUE(ExecuteScript(shell()->web_contents(), data_url_script));
184 void SitePerProcessBrowserTest::SetUpCommandLine(
185 base::CommandLine* command_line) {
186 command_line->AppendSwitch(switches::kSitePerProcess);
189 void SitePerProcessBrowserTest::SetUpOnMainThread() {
190 host_resolver()->AddRule("*", "127.0.0.1");
191 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
192 SetupCrossSiteRedirector(embedded_test_server());
195 // Ensure that navigating subframes in --site-per-process mode works and the
196 // correct documents are committed.
197 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteIframe) {
198 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
199 NavigateToURL(shell(), main_url);
201 // It is safe to obtain the root frame tree node here, as it doesn't change.
202 FrameTreeNode* root =
203 static_cast<WebContentsImpl*>(shell()->web_contents())->
204 GetFrameTree()->root();
206 TestNavigationObserver observer(shell()->web_contents());
208 // Load same-site page into iframe.
209 FrameTreeNode* child = root->child_at(0);
210 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
211 NavigateFrameToURL(child, http_url);
212 EXPECT_EQ(http_url, observer.last_navigation_url());
213 EXPECT_TRUE(observer.last_navigation_succeeded());
215 // There should be only one RenderWidgetHost when there are no
216 // cross-process iframes.
217 std::set<RenderWidgetHostView*> views_set =
218 static_cast<WebContentsImpl*>(shell()->web_contents())
219 ->GetRenderWidgetHostViewsInTree();
220 EXPECT_EQ(1U, views_set.size());
223 EXPECT_EQ(
224 " Site A\n"
225 " |--Site A\n"
226 " +--Site A\n"
227 " |--Site A\n"
228 " +--Site A\n"
229 " +--Site A\n"
230 "Where A = http://127.0.0.1/",
231 DepictFrameTree(root));
233 // Load cross-site page into iframe.
234 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
235 NavigateFrameToURL(root->child_at(0), url);
236 // Verify that the navigation succeeded and the expected URL was loaded.
237 EXPECT_TRUE(observer.last_navigation_succeeded());
238 EXPECT_EQ(url, observer.last_navigation_url());
240 // Ensure that we have created a new process for the subframe.
241 ASSERT_EQ(2U, root->child_count());
242 SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
243 RenderViewHost* rvh = child->current_frame_host()->render_view_host();
244 RenderProcessHost* rph = child->current_frame_host()->GetProcess();
245 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh);
246 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
247 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), rph);
249 // There should be now two RenderWidgetHosts, one for each process
250 // rendering a frame.
251 std::set<RenderWidgetHostView*> views_set =
252 static_cast<WebContentsImpl*>(shell()->web_contents())
253 ->GetRenderWidgetHostViewsInTree();
254 EXPECT_EQ(2U, views_set.size());
256 RenderFrameProxyHost* proxy_to_parent =
257 child->render_manager()->GetProxyToParent();
258 EXPECT_TRUE(proxy_to_parent);
259 EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
260 // The out-of-process iframe should have its own RenderWidgetHost,
261 // independent of any RenderViewHost.
262 EXPECT_NE(
263 rvh->GetView(),
264 proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
265 EXPECT_TRUE(child->current_frame_host()->GetRenderWidgetHost());
267 EXPECT_EQ(
268 " Site A ------------ proxies for B\n"
269 " |--Site B ------- proxies for A\n"
270 " +--Site A ------- proxies for B\n"
271 " |--Site A -- proxies for B\n"
272 " +--Site A -- proxies for B\n"
273 " +--Site A -- proxies for B\n"
274 "Where A = http://127.0.0.1/\n"
275 " B = http://foo.com/",
276 DepictFrameTree(root));
278 // Load another cross-site page into the same iframe.
279 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
280 NavigateFrameToURL(root->child_at(0), url);
281 EXPECT_TRUE(observer.last_navigation_succeeded());
282 EXPECT_EQ(url, observer.last_navigation_url());
284 // Check again that a new process is created and is different from the
285 // top level one and the previous one.
286 ASSERT_EQ(2U, root->child_count());
287 child = root->child_at(0);
288 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(),
289 child->current_frame_host()->render_view_host());
290 EXPECT_NE(rvh, child->current_frame_host()->render_view_host());
291 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
292 child->current_frame_host()->GetSiteInstance());
293 EXPECT_NE(site_instance,
294 child->current_frame_host()->GetSiteInstance());
295 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(),
296 child->current_frame_host()->GetProcess());
297 EXPECT_NE(rph, child->current_frame_host()->GetProcess());
299 std::set<RenderWidgetHostView*> views_set =
300 static_cast<WebContentsImpl*>(shell()->web_contents())
301 ->GetRenderWidgetHostViewsInTree();
302 EXPECT_EQ(2U, views_set.size());
304 EXPECT_EQ(proxy_to_parent, child->render_manager()->GetProxyToParent());
305 EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
306 EXPECT_NE(
307 child->current_frame_host()->render_view_host()->GetView(),
308 proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
309 EXPECT_TRUE(child->current_frame_host()->GetRenderWidgetHost());
311 EXPECT_EQ(
312 " Site A ------------ proxies for C\n"
313 " |--Site C ------- proxies for A\n"
314 " +--Site A ------- proxies for C\n"
315 " |--Site A -- proxies for C\n"
316 " +--Site A -- proxies for C\n"
317 " +--Site A -- proxies for C\n"
318 "Where A = http://127.0.0.1/\n"
319 " C = http://bar.com/",
320 DepictFrameTree(root));
323 // Tests OOPIF rendering by checking that the RWH of the iframe generates
324 // OnSwapCompositorFrame message.
325 #if defined(OS_ANDROID)
326 // http://crbug.com/471850
327 #define MAYBE_CompositorFrameSwapped DISABLED_CompositorFrameSwapped
328 #else
329 #define MAYBE_CompositorFrameSwapped CompositorFrameSwapped
330 #endif
331 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
332 MAYBE_CompositorFrameSwapped) {
333 GURL main_url(
334 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
335 NavigateToURL(shell(), main_url);
337 // It is safe to obtain the root frame tree node here, as it doesn't change.
338 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
339 ->GetFrameTree()
340 ->root();
341 ASSERT_EQ(1U, root->child_count());
343 FrameTreeNode* child_node = root->child_at(0);
344 GURL site_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
345 EXPECT_EQ(site_url, child_node->current_url());
346 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
347 child_node->current_frame_host()->GetSiteInstance());
348 RenderWidgetHostViewBase* rwhv_base = static_cast<RenderWidgetHostViewBase*>(
349 child_node->current_frame_host()->GetRenderWidgetHost()->GetView());
351 // Wait for OnSwapCompositorFrame message.
352 while (rwhv_base->RendererFrameNumber() <= 0) {
353 // TODO(lazyboy): Find a better way to avoid sleeping like this. See
354 // http://crbug.com/405282 for details.
355 base::RunLoop run_loop;
356 base::MessageLoop::current()->PostDelayedTask(
357 FROM_HERE, run_loop.QuitClosure(),
358 base::TimeDelta::FromMilliseconds(10));
359 run_loop.Run();
363 // Ensure that OOPIFs are deleted after navigating to a new main frame.
364 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CleanupCrossSiteIframe) {
365 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
366 NavigateToURL(shell(), main_url);
368 // It is safe to obtain the root frame tree node here, as it doesn't change.
369 FrameTreeNode* root =
370 static_cast<WebContentsImpl*>(shell()->web_contents())->
371 GetFrameTree()->root();
373 TestNavigationObserver observer(shell()->web_contents());
375 // Load a cross-site page into both iframes.
376 GURL foo_url = embedded_test_server()->GetURL("foo.com", "/title2.html");
377 NavigateFrameToURL(root->child_at(0), foo_url);
378 EXPECT_TRUE(observer.last_navigation_succeeded());
379 EXPECT_EQ(foo_url, observer.last_navigation_url());
380 NavigateFrameToURL(root->child_at(1), foo_url);
381 EXPECT_TRUE(observer.last_navigation_succeeded());
382 EXPECT_EQ(foo_url, observer.last_navigation_url());
384 // Ensure that we have created a new process for the subframes.
385 ASSERT_EQ(2U, root->child_count());
386 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
387 root->child_at(0)->current_frame_host()->GetSiteInstance());
388 EXPECT_EQ(root->child_at(0)->current_frame_host()->GetSiteInstance(),
389 root->child_at(1)->current_frame_host()->GetSiteInstance());
391 // Use Javascript in the parent to remove one of the frames and ensure that
392 // the subframe goes away.
393 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
394 "document.body.removeChild("
395 "document.querySelectorAll('iframe')[0])"));
396 ASSERT_EQ(1U, root->child_count());
398 // Load a new same-site page in the top-level frame and ensure the other
399 // subframe goes away.
400 GURL new_url(embedded_test_server()->GetURL("/title1.html"));
401 NavigateToURL(shell(), new_url);
402 ASSERT_EQ(0U, root->child_count());
405 // Ensure that root frames cannot be detached.
406 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, RestrictFrameDetach) {
407 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
408 NavigateToURL(shell(), main_url);
410 // It is safe to obtain the root frame tree node here, as it doesn't change.
411 FrameTreeNode* root =
412 static_cast<WebContentsImpl*>(shell()->web_contents())->
413 GetFrameTree()->root();
415 TestNavigationObserver observer(shell()->web_contents());
417 // Load cross-site pages into both iframes.
418 GURL foo_url = embedded_test_server()->GetURL("foo.com", "/title2.html");
419 NavigateFrameToURL(root->child_at(0), foo_url);
420 EXPECT_TRUE(observer.last_navigation_succeeded());
421 EXPECT_EQ(foo_url, observer.last_navigation_url());
422 GURL bar_url = embedded_test_server()->GetURL("bar.com", "/title2.html");
423 NavigateFrameToURL(root->child_at(1), bar_url);
424 EXPECT_TRUE(observer.last_navigation_succeeded());
425 EXPECT_EQ(bar_url, observer.last_navigation_url());
427 // Ensure that we have created new processes for the subframes.
428 ASSERT_EQ(2U, root->child_count());
429 FrameTreeNode* foo_child = root->child_at(0);
430 SiteInstance* foo_site_instance =
431 foo_child->current_frame_host()->GetSiteInstance();
432 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), foo_site_instance);
433 FrameTreeNode* bar_child = root->child_at(1);
434 SiteInstance* bar_site_instance =
435 bar_child->current_frame_host()->GetSiteInstance();
436 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), bar_site_instance);
438 // TODO(nick): The following EXPECTs are disabled because of
439 // http://crbug.com/476628, where the Site C node sometimes (flakily) has
440 // children even though it's committed a nav to a page with no iframes.
441 #if 0
442 EXPECT_EQ(
443 " Site A ------------ proxies for B C\n"
444 " |--Site B ------- proxies for A C\n"
445 " +--Site C ------- proxies for A B\n"
446 "Where A = http://127.0.0.1/\n"
447 " B = http://foo.com/\n"
448 " C = http://bar.com/",
449 DepictFrameTree(root));
450 #endif
452 // Simulate an attempt to detach the root frame from foo_site_instance. This
453 // should kill foo_site_instance's process.
454 RenderFrameProxyHost* foo_mainframe_rfph =
455 root->render_manager()->GetRenderFrameProxyHost(foo_site_instance);
456 content::RenderProcessHostWatcher foo_terminated(
457 foo_mainframe_rfph->GetProcess(),
458 content::RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
459 FrameHostMsg_Detach evil_msg2(foo_mainframe_rfph->GetRoutingID());
460 IPC::IpcSecurityTestUtil::PwnMessageReceived(
461 foo_mainframe_rfph->GetProcess()->GetChannel(), evil_msg2);
462 foo_terminated.Wait();
464 #if 0
465 EXPECT_EQ(
466 " Site A ------------ proxies for B C\n"
467 " |--Site B ------- proxies for A C\n"
468 " +--Site C ------- proxies for A B\n"
469 "Where A = http://127.0.0.1/\n"
470 " B = http://foo.com/ (no process)\n"
471 " C = http://bar.com/",
472 DepictFrameTree(root));
473 #endif
476 // Disabled for flaky crashing: crbug.com/446575
477 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
478 NavigateRemoteFrame) {
479 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
480 NavigateToURL(shell(), main_url);
482 // It is safe to obtain the root frame tree node here, as it doesn't change.
483 FrameTreeNode* root =
484 static_cast<WebContentsImpl*>(shell()->web_contents())->
485 GetFrameTree()->root();
487 TestNavigationObserver observer(shell()->web_contents());
489 // Load same-site page into iframe.
490 FrameTreeNode* child = root->child_at(0);
491 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
492 NavigateFrameToURL(child, http_url);
493 EXPECT_EQ(http_url, observer.last_navigation_url());
494 EXPECT_TRUE(observer.last_navigation_succeeded());
496 // Load cross-site page into iframe.
497 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
498 NavigateFrameToURL(root->child_at(0), url);
499 EXPECT_TRUE(observer.last_navigation_succeeded());
500 EXPECT_EQ(url, observer.last_navigation_url());
502 // Ensure that we have created a new process for the subframe.
503 ASSERT_EQ(2U, root->child_count());
504 SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
505 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
507 // Emulate the main frame changing the src of the iframe such that it
508 // navigates cross-site.
509 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
510 NavigateIframeToURL(shell()->web_contents(), "test", url);
511 EXPECT_TRUE(observer.last_navigation_succeeded());
512 EXPECT_EQ(url, observer.last_navigation_url());
514 // Check again that a new process is created and is different from the
515 // top level one and the previous one.
516 ASSERT_EQ(2U, root->child_count());
517 child = root->child_at(0);
518 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
519 child->current_frame_host()->GetSiteInstance());
520 EXPECT_NE(site_instance,
521 child->current_frame_host()->GetSiteInstance());
523 // Navigate back to the parent's origin and ensure we return to the
524 // parent's process.
525 NavigateFrameToURL(child, http_url);
526 EXPECT_EQ(http_url, observer.last_navigation_url());
527 EXPECT_TRUE(observer.last_navigation_succeeded());
528 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
529 child->current_frame_host()->GetSiteInstance());
532 #if defined(OS_WIN)
533 // http://crbug.com/446575
534 #define MAYBE_NavigateRemoteFrameToBlankAndDataURLs \
535 DISABLED_NavigateRemoteFrameToBlankAndDataURLs
536 #else
537 #define MAYBE_NavigateRemoteFrameToBlankAndDataURLs \
538 NavigateRemoteFrameToBlankAndDataURLs
539 #endif
541 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
542 MAYBE_NavigateRemoteFrameToBlankAndDataURLs) {
543 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
544 NavigateToURL(shell(), main_url);
546 // It is safe to obtain the root frame tree node here, as it doesn't change.
547 FrameTreeNode* root =
548 static_cast<WebContentsImpl*>(shell()->web_contents())->
549 GetFrameTree()->root();
551 TestNavigationObserver observer(shell()->web_contents());
553 // Load same-site page into iframe.
554 FrameTreeNode* child = root->child_at(0);
555 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
556 NavigateFrameToURL(child, http_url);
557 EXPECT_EQ(http_url, observer.last_navigation_url());
558 EXPECT_TRUE(observer.last_navigation_succeeded());
560 // Load cross-site page into iframe.
561 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
562 NavigateFrameToURL(root->child_at(0), url);
563 EXPECT_TRUE(observer.last_navigation_succeeded());
564 EXPECT_EQ(url, observer.last_navigation_url());
565 ASSERT_EQ(2U, root->child_count());
566 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
567 root->child_at(0)->current_frame_host()->GetSiteInstance());
569 // Navigate iframe to a data URL. The navigation happens from a script in the
570 // parent frame, so the data URL should be committed in the same SiteInstance
571 // as the parent frame.
572 GURL data_url("data:text/html,dataurl");
573 NavigateIframeToURL(shell()->web_contents(), "test", data_url);
574 EXPECT_TRUE(observer.last_navigation_succeeded());
575 EXPECT_EQ(data_url, observer.last_navigation_url());
577 // Ensure that we have navigated using the top level process.
578 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
579 root->child_at(0)->current_frame_host()->GetSiteInstance());
581 // Load cross-site page into iframe.
582 url = embedded_test_server()->GetURL("bar.com", "/title2.html");
583 NavigateFrameToURL(root->child_at(0), url);
584 EXPECT_TRUE(observer.last_navigation_succeeded());
585 EXPECT_EQ(url, observer.last_navigation_url());
586 ASSERT_EQ(2U, root->child_count());
587 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
588 root->child_at(0)->current_frame_host()->GetSiteInstance());
590 // Navigate iframe to about:blank. The navigation happens from a script in the
591 // parent frame, so it should be committed in the same SiteInstance as the
592 // parent frame.
593 GURL about_blank_url("about:blank");
594 NavigateIframeToURL(shell()->web_contents(), "test", about_blank_url);
595 EXPECT_TRUE(observer.last_navigation_succeeded());
596 EXPECT_EQ(about_blank_url, observer.last_navigation_url());
598 // Ensure that we have navigated using the top level process.
599 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
600 root->child_at(0)->current_frame_host()->GetSiteInstance());
603 // This test checks that killing a renderer process of a remote frame
604 // and then navigating some other frame to the same SiteInstance of the killed
605 // process works properly.
606 // This can be illustrated as follows,
607 // where 1/2/3 are FrameTreeNode-s and A/B are processes and B* is the killed
608 // B process:
610 // 1 A A A
611 // / \ -> / \ -> Kill B -> / \ -> Navigate 3 to B -> / \ .
612 // 2 3 B A B* A B* B
614 // Initially, node1.proxy_hosts_ = {B}
615 // After we kill B, we make sure B stays in node1.proxy_hosts_, then we navigate
616 // 3 to B and we expect that to complete normally.
617 // See http://crbug.com/432107.
619 // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
620 // site B and stays in not rendered state.
621 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
622 NavigateRemoteFrameToKilledProcess) {
623 GURL main_url(embedded_test_server()->GetURL(
624 "/frame_tree/page_with_two_frames.html"));
625 NavigateToURL(shell(), main_url);
627 // It is safe to obtain the root frame tree node here, as it doesn't change.
628 FrameTreeNode* root =
629 static_cast<WebContentsImpl*>(shell()->web_contents())->
630 GetFrameTree()->root();
632 TestNavigationObserver observer(shell()->web_contents());
633 ASSERT_EQ(2U, root->child_count());
635 // Make sure node2 points to the correct cross-site page.
636 GURL site_b_url = embedded_test_server()->GetURL("bar.com", "/title1.html");
637 FrameTreeNode* node2 = root->child_at(0);
638 EXPECT_EQ(site_b_url, node2->current_url());
640 // Kill that cross-site renderer.
641 RenderProcessHost* child_process =
642 node2->current_frame_host()->GetProcess();
643 RenderProcessHostWatcher crash_observer(
644 child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
645 child_process->Shutdown(0, false);
646 crash_observer.Wait();
648 // Now navigate the second iframe (node3) to the same site as the node2.
649 FrameTreeNode* node3 = root->child_at(1);
650 NavigateFrameToURL(node3, site_b_url);
651 EXPECT_TRUE(observer.last_navigation_succeeded());
652 EXPECT_EQ(site_b_url, observer.last_navigation_url());
655 // This test is similar to
656 // SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcess with
657 // addition that node2 also has a cross-origin frame to site C.
659 // 1 A A A
660 // / \ / \ / \ / \ .
661 // 2 3 -> B A -> Kill B -> B* A -> Navigate 3 -> B* B
662 // / /
663 // 4 C
665 // Initially, node1.proxy_hosts_ = {B, C}
666 // After we kill B, we make sure B stays in node1.proxy_hosts_, but
667 // C gets cleared from node1.proxy_hosts_.
669 // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
670 // site B and stays in not rendered state.
671 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
672 NavigateRemoteFrameToKilledProcessWithSubtree) {
673 GURL main_url(embedded_test_server()->GetURL(
674 "a.com", "/frame_tree/page_with_two_frames_nested.html"));
675 NavigateToURL(shell(), main_url);
677 // It is safe to obtain the root frame tree node here, as it doesn't change.
678 FrameTreeNode* root =
679 static_cast<WebContentsImpl*>(shell()->web_contents())->
680 GetFrameTree()->root();
681 TestNavigationObserver observer(shell()->web_contents());
683 ASSERT_EQ(2U, root->child_count());
685 GURL site_b_url(
686 embedded_test_server()->GetURL(
687 "bar.com", "/frame_tree/page_with_one_frame.html"));
688 // We can't use a TestNavigationObserver to verify the URL here,
689 // since the frame has children that may have clobbered it in the observer.
690 EXPECT_EQ(site_b_url, root->child_at(0)->current_url());
692 // Ensure that a new process is created for node2.
693 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
694 root->child_at(0)->current_frame_host()->GetSiteInstance());
695 // Ensure that a new process is *not* created for node3.
696 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
697 root->child_at(1)->current_frame_host()->GetSiteInstance());
699 ASSERT_EQ(1U, root->child_at(0)->child_count());
701 // Make sure node4 points to the correct cross-site page.
702 FrameTreeNode* node4 = root->child_at(0)->child_at(0);
703 GURL site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
704 EXPECT_EQ(site_c_url, node4->current_url());
706 // |site_instance_c| is expected to go away once we kill |child_process_b|
707 // below, so create a local scope so we can extend the lifetime of
708 // |site_instance_c| with a refptr.
710 // Initially each frame has proxies for the other sites.
711 EXPECT_EQ(
712 " Site A ------------ proxies for B C\n"
713 " |--Site B ------- proxies for A C\n"
714 " | +--Site C -- proxies for A B\n"
715 " +--Site A ------- proxies for B C\n"
716 "Where A = http://a.com/\n"
717 " B = http://bar.com/\n"
718 " C = http://baz.com/",
719 DepictFrameTree(root));
721 // Kill the render process for Site B.
722 RenderProcessHost* child_process_b =
723 root->child_at(0)->current_frame_host()->GetProcess();
724 RenderProcessHostWatcher crash_observer(
725 child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
726 child_process_b->Shutdown(0, false);
727 crash_observer.Wait();
729 // The Site C frame (a child of the crashed Site B frame) should go away,
730 // and there should be no remaining proxies for site C anywhere.
731 EXPECT_EQ(
732 " Site A ------------ proxies for B\n"
733 " |--Site B ------- proxies for A\n"
734 " +--Site A ------- proxies for B\n"
735 "Where A = http://a.com/\n"
736 " B = http://bar.com/ (no process)",
737 DepictFrameTree(root));
740 // Now navigate the second iframe (node3) to Site B also.
741 FrameTreeNode* node3 = root->child_at(1);
742 GURL url = embedded_test_server()->GetURL("bar.com", "/title1.html");
743 NavigateFrameToURL(node3, url);
744 EXPECT_TRUE(observer.last_navigation_succeeded());
745 EXPECT_EQ(url, observer.last_navigation_url());
747 EXPECT_EQ(
748 " Site A ------------ proxies for B\n"
749 " |--Site B ------- proxies for A\n"
750 " +--Site B ------- proxies for A\n"
751 "Where A = http://a.com/\n"
752 " B = http://bar.com/",
753 DepictFrameTree(root));
756 // In A-embed-B-embed-C scenario, verify that killing process B clears proxies
757 // of C from the tree.
759 // 1 A A
760 // / \ / \ / \ .
761 // 2 3 -> B A -> Kill B -> B* A
762 // / /
763 // 4 C
765 // node1 is the root.
766 // Initially, both node1.proxy_hosts_ and node3.proxy_hosts_ contain C.
767 // After we kill B, make sure proxies for C are cleared.
768 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
769 KillingRendererClearsDescendantProxies) {
770 GURL main_url(embedded_test_server()->GetURL(
771 "a.com", "/frame_tree/page_with_two_frames_nested.html"));
772 NavigateToURL(shell(), main_url);
774 // It is safe to obtain the root frame tree node here, as it doesn't change.
775 FrameTreeNode* root =
776 static_cast<WebContentsImpl*>(shell()->web_contents())->
777 GetFrameTree()->root();
778 TestNavigationObserver observer(shell()->web_contents());
780 ASSERT_EQ(2U, root->child_count());
782 GURL site_b_url(
783 embedded_test_server()->GetURL(
784 "bar.com", "/frame_tree/page_with_one_frame.html"));
785 // We can't use a TestNavigationObserver to verify the URL here,
786 // since the frame has children that may have clobbered it in the observer.
787 EXPECT_EQ(site_b_url, root->child_at(0)->current_url());
789 // Ensure that a new process is created for node2.
790 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
791 root->child_at(0)->current_frame_host()->GetSiteInstance());
792 // Ensure that a new process is *not* created for node3.
793 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
794 root->child_at(1)->current_frame_host()->GetSiteInstance());
796 ASSERT_EQ(1U, root->child_at(0)->child_count());
798 // Make sure node4 points to the correct cross-site-page.
799 FrameTreeNode* node4 = root->child_at(0)->child_at(0);
800 GURL site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
801 EXPECT_EQ(site_c_url, node4->current_url());
803 // |site_instance_c| is expected to go away once we kill |child_process_b|
804 // below; refcount it to extend the lifetime.
805 scoped_refptr<SiteInstanceImpl> site_instance_c =
806 node4->current_frame_host()->GetSiteInstance();
808 // Initially proxies for both B and C will be present in the root.
809 EXPECT_EQ(
810 " Site A ------------ proxies for B C\n"
811 " |--Site B ------- proxies for A C\n"
812 " | +--Site C -- proxies for A B\n"
813 " +--Site A ------- proxies for B C\n"
814 "Where A = http://a.com/\n"
815 " B = http://bar.com/\n"
816 " C = http://baz.com/",
817 DepictFrameTree(root));
818 // Kill process B.
819 RenderProcessHost* child_process_b =
820 root->child_at(0)->current_frame_host()->GetProcess();
821 RenderProcessHostWatcher crash_observer(
822 child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
823 child_process_b->Shutdown(0, false);
824 crash_observer.Wait();
826 // Make sure proxy C has gone from root.
827 // Make sure proxy C has gone from node3 as well.
828 // Make sure proxy B stays around in root and node3.
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 "Where A = http://a.com/\n"
834 " B = http://bar.com/ (no process)",
835 DepictFrameTree(root));
837 EXPECT_TRUE(site_instance_c->HasOneRef());
840 // Crash a subframe and ensures its children are cleared from the FrameTree.
841 // See http://crbug.com/338508.
842 // TODO(creis): Disabled for flakiness; see http://crbug.com/405582.
843 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DISABLED_CrashSubframe) {
844 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
845 NavigateToURL(shell(), main_url);
847 StartFrameAtDataURL();
849 // These must stay in scope with replace_host.
850 GURL::Replacements replace_host;
851 std::string foo_com("foo.com");
853 // Load cross-site page into iframe.
854 EXPECT_TRUE(NavigateIframeToURL(
855 shell()->web_contents(), "test",
856 embedded_test_server()->GetURL("/cross-site/foo.com/title2.html")));
858 // Check the subframe process.
859 FrameTreeNode* root =
860 static_cast<WebContentsImpl*>(shell()->web_contents())->
861 GetFrameTree()->root();
862 ASSERT_EQ(2U, root->child_count());
863 FrameTreeNode* child = root->child_at(0);
864 EXPECT_EQ(main_url, root->current_url());
865 EXPECT_EQ("foo.com", child->current_url().host());
866 EXPECT_EQ("/title2.html", child->current_url().path());
868 EXPECT_TRUE(
869 child->current_frame_host()->render_view_host()->IsRenderViewLive());
870 EXPECT_TRUE(child->current_frame_host()->IsRenderFrameLive());
872 // Crash the subframe process.
873 RenderProcessHost* root_process = root->current_frame_host()->GetProcess();
874 RenderProcessHost* child_process = child->current_frame_host()->GetProcess();
876 RenderProcessHostWatcher crash_observer(
877 child_process,
878 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
879 child_process->Shutdown(0, false);
880 crash_observer.Wait();
883 // Ensure that the child frame still exists but has been cleared.
884 EXPECT_EQ(2U, root->child_count());
885 EXPECT_EQ(main_url, root->current_url());
886 EXPECT_EQ(GURL(), child->current_url());
888 EXPECT_FALSE(
889 child->current_frame_host()->render_view_host()->IsRenderViewLive());
890 EXPECT_FALSE(child->current_frame_host()->IsRenderFrameLive());
891 EXPECT_FALSE(child->current_frame_host()->render_frame_created_);
893 // Now crash the top-level page to clear the child frame.
895 RenderProcessHostWatcher crash_observer(
896 root_process,
897 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
898 root_process->Shutdown(0, false);
899 crash_observer.Wait();
901 EXPECT_EQ(0U, root->child_count());
902 EXPECT_EQ(GURL(), root->current_url());
905 // When a new subframe is added, related SiteInstances that can reach the
906 // subframe should create proxies for it (https://crbug.com/423587). This test
907 // checks that if A embeds B and later adds a new subframe A2, A2 gets a proxy
908 // in B's process.
909 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CreateProxiesForNewFrames) {
910 GURL main_url(embedded_test_server()->GetURL(
911 "b.com", "/frame_tree/page_with_one_frame.html"));
912 EXPECT_TRUE(NavigateToURL(shell(), main_url));
914 // It is safe to obtain the root frame tree node here, as it doesn't change.
915 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
916 ->GetFrameTree()
917 ->root();
918 ASSERT_EQ(1U, root->child_count());
920 // Make sure the frame starts out at the correct cross-site URL.
921 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"),
922 root->child_at(0)->current_url());
924 EXPECT_EQ(
925 " Site A ------------ proxies for B\n"
926 " +--Site B ------- proxies for A\n"
927 "Where A = http://b.com/\n"
928 " B = http://baz.com/",
929 DepictFrameTree(root));
931 // Add a new child frame to the top-level frame.
932 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 1);
933 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
934 "window.domAutomationController.send("
935 " addFrame('data:text/html,foo'));"));
936 frame_observer.Wait();
938 // The new frame should have a proxy in Site B, for use by the old frame.
939 EXPECT_EQ(
940 " Site A ------------ proxies for B\n"
941 " |--Site B ------- proxies for A\n"
942 " +--Site A ------- proxies for B\n"
943 "Where A = http://b.com/\n"
944 " B = http://baz.com/",
945 DepictFrameTree(root));
948 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
949 // security checks are back in place.
950 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
951 // on Android (http://crbug.com/187570).
952 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
953 DISABLED_CrossSiteIframeRedirectOnce) {
954 ASSERT_TRUE(test_server()->Start());
955 net::SpawnedTestServer https_server(
956 net::SpawnedTestServer::TYPE_HTTPS,
957 net::SpawnedTestServer::kLocalhost,
958 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
959 ASSERT_TRUE(https_server.Start());
961 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
962 GURL http_url(test_server()->GetURL("files/title1.html"));
963 GURL https_url(https_server.GetURL("files/title1.html"));
965 NavigateToURL(shell(), main_url);
967 TestNavigationObserver observer(shell()->web_contents());
969 // Load cross-site client-redirect page into Iframe.
970 // Should be blocked.
971 GURL client_redirect_https_url(https_server.GetURL(
972 "client-redirect?files/title1.html"));
973 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
974 client_redirect_https_url));
975 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
976 EXPECT_EQ(observer.last_navigation_url(), client_redirect_https_url);
977 EXPECT_FALSE(observer.last_navigation_succeeded());
981 // Load cross-site server-redirect page into Iframe,
982 // which redirects to same-site page.
983 GURL server_redirect_http_url(https_server.GetURL(
984 "server-redirect?" + http_url.spec()));
985 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
986 server_redirect_http_url));
987 EXPECT_EQ(observer.last_navigation_url(), http_url);
988 EXPECT_TRUE(observer.last_navigation_succeeded());
992 // Load cross-site server-redirect page into Iframe,
993 // which redirects to cross-site page.
994 GURL server_redirect_http_url(https_server.GetURL(
995 "server-redirect?files/title1.html"));
996 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
997 server_redirect_http_url));
998 // DidFailProvisionalLoad when navigating to https_url.
999 EXPECT_EQ(observer.last_navigation_url(), https_url);
1000 EXPECT_FALSE(observer.last_navigation_succeeded());
1004 // Load same-site server-redirect page into Iframe,
1005 // which redirects to cross-site page.
1006 GURL server_redirect_http_url(test_server()->GetURL(
1007 "server-redirect?" + https_url.spec()));
1008 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1009 server_redirect_http_url));
1011 EXPECT_EQ(observer.last_navigation_url(), https_url);
1012 EXPECT_FALSE(observer.last_navigation_succeeded());
1016 // Load same-site client-redirect page into Iframe,
1017 // which redirects to cross-site page.
1018 GURL client_redirect_http_url(test_server()->GetURL(
1019 "client-redirect?" + https_url.spec()));
1021 RedirectNotificationObserver load_observer2(
1022 NOTIFICATION_LOAD_STOP,
1023 Source<NavigationController>(
1024 &shell()->web_contents()->GetController()));
1026 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1027 client_redirect_http_url));
1029 // Same-site Client-Redirect Page should be loaded successfully.
1030 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
1031 EXPECT_TRUE(observer.last_navigation_succeeded());
1033 // Redirecting to Cross-site Page should be blocked.
1034 load_observer2.Wait();
1035 EXPECT_EQ(observer.last_navigation_url(), https_url);
1036 EXPECT_FALSE(observer.last_navigation_succeeded());
1040 // Load same-site server-redirect page into Iframe,
1041 // which redirects to same-site page.
1042 GURL server_redirect_http_url(test_server()->GetURL(
1043 "server-redirect?files/title1.html"));
1044 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1045 server_redirect_http_url));
1046 EXPECT_EQ(observer.last_navigation_url(), http_url);
1047 EXPECT_TRUE(observer.last_navigation_succeeded());
1051 // Load same-site client-redirect page into Iframe,
1052 // which redirects to same-site page.
1053 GURL client_redirect_http_url(test_server()->GetURL(
1054 "client-redirect?" + http_url.spec()));
1055 RedirectNotificationObserver load_observer2(
1056 NOTIFICATION_LOAD_STOP,
1057 Source<NavigationController>(
1058 &shell()->web_contents()->GetController()));
1060 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1061 client_redirect_http_url));
1063 // Same-site Client-Redirect Page should be loaded successfully.
1064 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
1065 EXPECT_TRUE(observer.last_navigation_succeeded());
1067 // Redirecting to Same-site Page should be loaded successfully.
1068 load_observer2.Wait();
1069 EXPECT_EQ(observer.last_navigation_url(), http_url);
1070 EXPECT_TRUE(observer.last_navigation_succeeded());
1074 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
1075 // security checks are back in place.
1076 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
1077 // on Android (http://crbug.com/187570).
1078 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1079 DISABLED_CrossSiteIframeRedirectTwice) {
1080 ASSERT_TRUE(test_server()->Start());
1081 net::SpawnedTestServer https_server(
1082 net::SpawnedTestServer::TYPE_HTTPS,
1083 net::SpawnedTestServer::kLocalhost,
1084 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
1085 ASSERT_TRUE(https_server.Start());
1087 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
1088 GURL http_url(test_server()->GetURL("files/title1.html"));
1089 GURL https_url(https_server.GetURL("files/title1.html"));
1091 NavigateToURL(shell(), main_url);
1093 TestNavigationObserver observer(shell()->web_contents());
1095 // Load client-redirect page pointing to a cross-site client-redirect page,
1096 // which eventually redirects back to same-site page.
1097 GURL client_redirect_https_url(https_server.GetURL(
1098 "client-redirect?" + http_url.spec()));
1099 GURL client_redirect_http_url(test_server()->GetURL(
1100 "client-redirect?" + client_redirect_https_url.spec()));
1102 // We should wait until second client redirect get cancelled.
1103 RedirectNotificationObserver load_observer2(
1104 NOTIFICATION_LOAD_STOP,
1105 Source<NavigationController>(
1106 &shell()->web_contents()->GetController()));
1108 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1109 client_redirect_http_url));
1111 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
1112 load_observer2.Wait();
1113 EXPECT_EQ(observer.last_navigation_url(), client_redirect_https_url);
1114 EXPECT_FALSE(observer.last_navigation_succeeded());
1118 // Load server-redirect page pointing to a cross-site server-redirect page,
1119 // which eventually redirect back to same-site page.
1120 GURL server_redirect_https_url(https_server.GetURL(
1121 "server-redirect?" + http_url.spec()));
1122 GURL server_redirect_http_url(test_server()->GetURL(
1123 "server-redirect?" + server_redirect_https_url.spec()));
1124 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1125 server_redirect_http_url));
1126 EXPECT_EQ(observer.last_navigation_url(), http_url);
1127 EXPECT_TRUE(observer.last_navigation_succeeded());
1131 // Load server-redirect page pointing to a cross-site server-redirect page,
1132 // which eventually redirects back to cross-site page.
1133 GURL server_redirect_https_url(https_server.GetURL(
1134 "server-redirect?" + https_url.spec()));
1135 GURL server_redirect_http_url(test_server()->GetURL(
1136 "server-redirect?" + server_redirect_https_url.spec()));
1137 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1138 server_redirect_http_url));
1140 // DidFailProvisionalLoad when navigating to https_url.
1141 EXPECT_EQ(observer.last_navigation_url(), https_url);
1142 EXPECT_FALSE(observer.last_navigation_succeeded());
1146 // Load server-redirect page pointing to a cross-site client-redirect page,
1147 // which eventually redirects back to same-site page.
1148 GURL client_redirect_http_url(https_server.GetURL(
1149 "client-redirect?" + http_url.spec()));
1150 GURL server_redirect_http_url(test_server()->GetURL(
1151 "server-redirect?" + client_redirect_http_url.spec()));
1152 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
1153 server_redirect_http_url));
1155 // DidFailProvisionalLoad when navigating to client_redirect_http_url.
1156 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
1157 EXPECT_FALSE(observer.last_navigation_succeeded());
1161 // Ensure that when navigating a frame cross-process RenderFrameProxyHosts are
1162 // created in the FrameTree skipping the subtree of the navigating frame.
1164 // Disabled on Mac due to flakiness on ASAN. http://crbug.com/425248
1165 // Disabled on Windows due to flakiness on Win 7 bot. http://crbug.com/444563
1166 #if defined(OS_MACOSX) || defined(OS_WIN)
1167 #define MAYBE_ProxyCreationSkipsSubtree DISABLED_ProxyCreationSkipsSubtree
1168 #else
1169 #define MAYBE_ProxyCreationSkipsSubtree ProxyCreationSkipsSubtree
1170 #endif
1171 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1172 MAYBE_ProxyCreationSkipsSubtree) {
1173 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1174 NavigateToURL(shell(), main_url);
1176 // It is safe to obtain the root frame tree node here, as it doesn't change.
1177 FrameTreeNode* root =
1178 static_cast<WebContentsImpl*>(shell()->web_contents())->
1179 GetFrameTree()->root();
1181 EXPECT_TRUE(root->child_at(1) != NULL);
1182 EXPECT_EQ(2U, root->child_at(1)->child_count());
1185 // Load same-site page into iframe.
1186 TestNavigationObserver observer(shell()->web_contents());
1187 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
1188 NavigateFrameToURL(root->child_at(0), http_url);
1189 EXPECT_EQ(http_url, observer.last_navigation_url());
1190 EXPECT_TRUE(observer.last_navigation_succeeded());
1191 EXPECT_EQ(
1192 " Site A\n"
1193 " |--Site A\n"
1194 " +--Site A\n"
1195 " |--Site A\n"
1196 " +--Site A\n"
1197 " +--Site A\n"
1198 "Where A = http://127.0.0.1/",
1199 DepictFrameTree(root));
1202 // Create the cross-site URL to navigate to.
1203 GURL cross_site_url =
1204 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html");
1206 // Load cross-site page into the second iframe without waiting for the
1207 // navigation to complete. Once LoadURLWithParams returns, we would expect
1208 // proxies to have been created in the frame tree, but children of the
1209 // navigating frame to still be present. The reason is that we don't run the
1210 // message loop, so no IPCs that alter the frame tree can be processed.
1211 FrameTreeNode* child = root->child_at(1);
1212 SiteInstance* site = NULL;
1214 TestNavigationObserver observer(shell()->web_contents());
1215 TestFrameNavigationObserver navigation_observer(child);
1216 NavigationController::LoadURLParams params(cross_site_url);
1217 params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
1218 params.frame_tree_node_id = child->frame_tree_node_id();
1219 child->navigator()->GetController()->LoadURLWithParams(params);
1221 site = child->render_manager()->pending_frame_host()->GetSiteInstance();
1222 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site);
1224 EXPECT_EQ(
1225 " Site A ------------ proxies for B\n"
1226 " |--Site A ------- proxies for B\n"
1227 " +--Site A (B pending)\n"
1228 " |--Site A\n"
1229 " +--Site A\n"
1230 " +--Site A\n"
1231 "Where A = http://127.0.0.1/\n"
1232 " B = http://foo.com/",
1233 DepictFrameTree(root));
1235 // Now that the verification is done, run the message loop and wait for the
1236 // navigation to complete.
1237 navigation_observer.Wait();
1238 EXPECT_FALSE(child->render_manager()->pending_frame_host());
1239 EXPECT_TRUE(observer.last_navigation_succeeded());
1240 EXPECT_EQ(cross_site_url, observer.last_navigation_url());
1243 // Load another cross-site page into the same iframe.
1244 cross_site_url = embedded_test_server()->GetURL("bar.com", "/title2.html");
1246 // Perform the same checks as the first cross-site navigation, since
1247 // there have been issues in subsequent cross-site navigations. Also ensure
1248 // that the SiteInstance has properly changed.
1249 // TODO(nasko): Once we have proper cleanup of resources, add code to
1250 // verify that the intermediate SiteInstance/RenderFrameHost have been
1251 // properly cleaned up.
1252 TestNavigationObserver observer(shell()->web_contents());
1253 TestFrameNavigationObserver navigation_observer(child);
1254 NavigationController::LoadURLParams params(cross_site_url);
1255 params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
1256 params.frame_tree_node_id = child->frame_tree_node_id();
1257 child->navigator()->GetController()->LoadURLWithParams(params);
1259 SiteInstance* site2 =
1260 child->render_manager()->pending_frame_host()->GetSiteInstance();
1261 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site2);
1262 EXPECT_NE(site, site2);
1264 EXPECT_EQ(
1265 " Site A ------------ proxies for B C\n"
1266 " |--Site A ------- proxies for B C\n"
1267 " +--Site B (C pending) -- proxies for A\n"
1268 " |--Site A\n"
1269 " +--Site A\n"
1270 " +--Site A\n"
1271 "Where A = http://127.0.0.1/\n"
1272 " B = http://foo.com/\n"
1273 " C = http://bar.com/",
1274 DepictFrameTree(root));
1276 navigation_observer.Wait();
1277 EXPECT_TRUE(observer.last_navigation_succeeded());
1278 EXPECT_EQ(cross_site_url, observer.last_navigation_url());
1279 EXPECT_EQ(0U, child->child_count());
1283 // Verify that origin replication works for an A-embed-B-embed-C hierarchy.
1284 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OriginReplication) {
1285 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1286 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1288 // It is safe to obtain the root frame tree node here, as it doesn't change.
1289 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1290 ->GetFrameTree()
1291 ->root();
1293 TestNavigationObserver observer(shell()->web_contents());
1295 // Navigate the first subframe to a cross-site page with two subframes.
1296 // NavigateFrameToURL can't be used here because it doesn't guarantee that
1297 // FrameTreeNodes will have been created for child frames when it returns.
1298 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 4);
1299 GURL foo_url(
1300 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
1301 NavigationController::LoadURLParams params(foo_url);
1302 params.transition_type = ui::PAGE_TRANSITION_LINK;
1303 params.frame_tree_node_id = root->child_at(0)->frame_tree_node_id();
1304 root->child_at(0)->navigator()->GetController()->LoadURLWithParams(params);
1305 frame_observer.Wait();
1307 // We can't use a TestNavigationObserver to verify the URL here,
1308 // since the frame has children that may have clobbered it in the observer.
1309 EXPECT_EQ(foo_url, root->child_at(0)->current_url());
1311 // Ensure that a new process is created for the subframe.
1312 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1313 root->child_at(0)->current_frame_host()->GetSiteInstance());
1315 // Load cross-site page into subframe's subframe.
1316 ASSERT_EQ(2U, root->child_at(0)->child_count());
1317 GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
1318 NavigateFrameToURL(root->child_at(0)->child_at(0), bar_url);
1319 EXPECT_TRUE(observer.last_navigation_succeeded());
1320 EXPECT_EQ(bar_url, observer.last_navigation_url());
1322 // Check that a new process is created and is different from the top one and
1323 // the middle one.
1324 FrameTreeNode* bottom_child = root->child_at(0)->child_at(0);
1325 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1326 bottom_child->current_frame_host()->GetSiteInstance());
1327 EXPECT_NE(root->child_at(0)->current_frame_host()->GetSiteInstance(),
1328 bottom_child->current_frame_host()->GetSiteInstance());
1330 // Check that foo.com frame's location.ancestorOrigins contains the correct
1331 // origin for the parent. The origin should have been replicated as part of
1332 // the ViewMsg_New message that created the parent's RenderFrameProxy in
1333 // foo.com's process.
1334 int ancestor_origins_length = 0;
1335 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1336 root->child_at(0)->current_frame_host(),
1337 "window.domAutomationController.send(location.ancestorOrigins.length);",
1338 &ancestor_origins_length));
1339 EXPECT_EQ(1, ancestor_origins_length);
1340 std::string result;
1341 EXPECT_TRUE(ExecuteScriptAndExtractString(
1342 root->child_at(0)->current_frame_host(),
1343 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1344 &result));
1345 EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
1347 // Check that bar.com frame's location.ancestorOrigins contains the correct
1348 // origin for its two ancestors. The topmost parent origin should be
1349 // replicated as part of ViewMsg_New, and the middle frame (foo.com's) origin
1350 // should be replicated as part of FrameMsg_NewFrameProxy sent for foo.com's
1351 // frame in bar.com's process.
1352 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1353 bottom_child->current_frame_host(),
1354 "window.domAutomationController.send(location.ancestorOrigins.length);",
1355 &ancestor_origins_length));
1356 EXPECT_EQ(2, ancestor_origins_length);
1357 EXPECT_TRUE(ExecuteScriptAndExtractString(
1358 bottom_child->current_frame_host(),
1359 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1360 &result));
1361 EXPECT_EQ(result + "/", foo_url.GetOrigin().spec());
1362 EXPECT_TRUE(ExecuteScriptAndExtractString(
1363 bottom_child->current_frame_host(),
1364 "window.domAutomationController.send(location.ancestorOrigins[1]);",
1365 &result));
1366 EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
1369 // Check that iframe sandbox flags are replicated correctly.
1370 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SandboxFlagsReplication) {
1371 GURL main_url(embedded_test_server()->GetURL("/sandboxed_frames.html"));
1372 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1374 // It is safe to obtain the root frame tree node here, as it doesn't change.
1375 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1376 ->GetFrameTree()
1377 ->root();
1379 TestNavigationObserver observer(shell()->web_contents());
1381 // Navigate the second (sandboxed) subframe to a cross-site page with a
1382 // subframe. Use RenderFrameHostCreatedObserver to guarantee that all
1383 // FrameTreeNodes are created for child frames.
1384 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 4);
1385 GURL foo_url(
1386 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
1387 NavigateFrameToURL(root->child_at(1), foo_url);
1388 frame_observer.Wait();
1390 // We can't use a TestNavigationObserver to verify the URL here,
1391 // since the frame has children that may have clobbered it in the observer.
1392 EXPECT_EQ(foo_url, root->child_at(1)->current_url());
1394 // Load cross-site page into subframe's subframe.
1395 ASSERT_EQ(2U, root->child_at(1)->child_count());
1396 GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
1397 NavigateFrameToURL(root->child_at(1)->child_at(0), bar_url);
1398 EXPECT_TRUE(observer.last_navigation_succeeded());
1399 EXPECT_EQ(bar_url, observer.last_navigation_url());
1401 // Opening a popup in the sandboxed foo.com iframe should fail.
1402 bool success = false;
1403 EXPECT_TRUE(
1404 ExecuteScriptAndExtractBool(root->child_at(1)->current_frame_host(),
1405 "window.domAutomationController.send("
1406 "!window.open('data:text/html,dataurl'));",
1407 &success));
1408 EXPECT_TRUE(success);
1409 EXPECT_EQ(1u, Shell::windows().size());
1411 // Opening a popup in a frame whose parent is sandboxed should also fail.
1412 // Here, bar.com frame's sandboxed parent frame is a remote frame in
1413 // bar.com's process.
1414 success = false;
1415 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1416 root->child_at(1)->child_at(0)->current_frame_host(),
1417 "window.domAutomationController.send("
1418 "!window.open('data:text/html,dataurl'));",
1419 &success));
1420 EXPECT_TRUE(success);
1421 EXPECT_EQ(1u, Shell::windows().size());
1423 // Same, but now try the case where bar.com frame's sandboxed parent is a
1424 // local frame in bar.com's process.
1425 success = false;
1426 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1427 root->child_at(2)->child_at(0)->current_frame_host(),
1428 "window.domAutomationController.send("
1429 "!window.open('data:text/html,dataurl'));",
1430 &success));
1431 EXPECT_TRUE(success);
1432 EXPECT_EQ(1u, Shell::windows().size());
1434 // Check that foo.com frame's location.ancestorOrigins contains the correct
1435 // origin for the parent, which should be unaffected by sandboxing.
1436 int ancestor_origins_length = 0;
1437 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1438 root->child_at(1)->current_frame_host(),
1439 "window.domAutomationController.send(location.ancestorOrigins.length);",
1440 &ancestor_origins_length));
1441 EXPECT_EQ(1, ancestor_origins_length);
1442 std::string result;
1443 EXPECT_TRUE(ExecuteScriptAndExtractString(
1444 root->child_at(1)->current_frame_host(),
1445 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1446 &result));
1447 EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
1449 // Now check location.ancestorOrigins for the bar.com frame. The middle frame
1450 // (foo.com's) origin should be unique, since that frame is sandboxed, and
1451 // the top frame should match |main_url|.
1452 FrameTreeNode* bottom_child = root->child_at(1)->child_at(0);
1453 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1454 bottom_child->current_frame_host(),
1455 "window.domAutomationController.send(location.ancestorOrigins.length);",
1456 &ancestor_origins_length));
1457 EXPECT_EQ(2, ancestor_origins_length);
1458 EXPECT_TRUE(ExecuteScriptAndExtractString(
1459 bottom_child->current_frame_host(),
1460 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1461 &result));
1462 EXPECT_EQ("null", result);
1463 EXPECT_TRUE(ExecuteScriptAndExtractString(
1464 bottom_child->current_frame_host(),
1465 "window.domAutomationController.send(location.ancestorOrigins[1]);",
1466 &result));
1467 EXPECT_EQ(main_url.GetOrigin().spec(), result + "/");
1470 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
1471 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicSandboxFlags) {
1472 GURL main_url(
1473 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
1474 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1476 // It is safe to obtain the root frame tree node here, as it doesn't change.
1477 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1478 ->GetFrameTree()
1479 ->root();
1481 TestNavigationObserver observer(shell()->web_contents());
1482 ASSERT_EQ(2U, root->child_count());
1484 // Make sure first frame starts out at the correct cross-site page.
1485 EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"),
1486 root->child_at(0)->current_url());
1488 // Navigate second frame to another cross-site page.
1489 GURL baz_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
1490 NavigateFrameToURL(root->child_at(1), baz_url);
1491 EXPECT_TRUE(observer.last_navigation_succeeded());
1492 EXPECT_EQ(baz_url, observer.last_navigation_url());
1494 // Both frames should not be sandboxed to start with.
1495 EXPECT_EQ(SandboxFlags::NONE,
1496 root->child_at(0)->current_replication_state().sandbox_flags);
1497 EXPECT_EQ(SandboxFlags::NONE, root->child_at(0)->effective_sandbox_flags());
1498 EXPECT_EQ(SandboxFlags::NONE,
1499 root->child_at(1)->current_replication_state().sandbox_flags);
1500 EXPECT_EQ(SandboxFlags::NONE, root->child_at(1)->effective_sandbox_flags());
1502 // Dynamically update sandbox flags for the first frame.
1503 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1504 "window.domAutomationController.send("
1505 "document.querySelector('iframe').sandbox="
1506 "'allow-scripts');"));
1508 // Check that updated sandbox flags are propagated to browser process.
1509 // The new flags should be set in current_replication_state(), while
1510 // effective_sandbox_flags() should still reflect the old flags, because
1511 // sandbox flag updates take place only after navigations. "allow-scripts"
1512 // resets both SandboxFlags::Scripts and SandboxFlags::AutomaticFeatures bits
1513 // per blink::parseSandboxPolicy().
1514 SandboxFlags expected_flags = SandboxFlags::ALL & ~SandboxFlags::SCRIPTS &
1515 ~SandboxFlags::AUTOMATIC_FEATURES;
1516 EXPECT_EQ(expected_flags,
1517 root->child_at(0)->current_replication_state().sandbox_flags);
1518 EXPECT_EQ(SandboxFlags::NONE, root->child_at(0)->effective_sandbox_flags());
1520 // Navigate the first frame to a page on the same site. The new sandbox
1521 // flags should take effect. The new page has a child frame, so use
1522 // TestFrameNavigationObserver to wait for it to be loaded.
1523 TestFrameNavigationObserver frame_observer(root->child_at(0), 2);
1524 GURL bar_url(
1525 embedded_test_server()->GetURL("bar.com", "/frame_tree/2-4.html"));
1526 NavigateFrameToURL(root->child_at(0), bar_url);
1527 frame_observer.Wait();
1528 EXPECT_EQ(bar_url, root->child_at(0)->current_url());
1529 ASSERT_EQ(1U, root->child_at(0)->child_count());
1531 // Confirm that the browser process has updated the frame's current sandbox
1532 // flags.
1533 EXPECT_EQ(expected_flags,
1534 root->child_at(0)->current_replication_state().sandbox_flags);
1535 EXPECT_EQ(expected_flags, root->child_at(0)->effective_sandbox_flags());
1537 // Opening a popup in the now-sandboxed frame should fail.
1538 bool success = false;
1539 EXPECT_TRUE(
1540 ExecuteScriptAndExtractBool(root->child_at(0)->current_frame_host(),
1541 "window.domAutomationController.send("
1542 "!window.open('data:text/html,dataurl'));",
1543 &success));
1544 EXPECT_TRUE(success);
1545 EXPECT_EQ(1u, Shell::windows().size());
1547 // Navigate the child of the now-sandboxed frame to a page on baz.com. The
1548 // child should inherit the latest sandbox flags from its parent frame, which
1549 // is currently a proxy in baz.com's renderer process. This checks that the
1550 // proxies of |root->child_at(0)| were also updated with the latest sandbox
1551 // flags.
1552 GURL baz_child_url(embedded_test_server()->GetURL("baz.com", "/title2.html"));
1553 NavigateFrameToURL(root->child_at(0)->child_at(0), baz_child_url);
1554 EXPECT_TRUE(observer.last_navigation_succeeded());
1555 EXPECT_EQ(baz_child_url, observer.last_navigation_url());
1557 // Opening a popup in the child of a sandboxed frame should fail.
1558 success = false;
1559 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1560 root->child_at(0)->child_at(0)->current_frame_host(),
1561 "window.domAutomationController.send("
1562 "!window.open('data:text/html,dataurl'));",
1563 &success));
1564 EXPECT_TRUE(success);
1565 EXPECT_EQ(1u, Shell::windows().size());
1568 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
1569 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1570 DynamicSandboxFlagsRemoteToLocal) {
1571 GURL main_url(
1572 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
1573 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1575 // It is safe to obtain the root frame tree node here, as it doesn't change.
1576 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1577 ->GetFrameTree()
1578 ->root();
1580 TestNavigationObserver observer(shell()->web_contents());
1581 ASSERT_EQ(2U, root->child_count());
1583 // Make sure the two frames starts out at correct URLs.
1584 EXPECT_EQ(embedded_test_server()->GetURL("bar.com", "/title1.html"),
1585 root->child_at(0)->current_url());
1586 EXPECT_EQ(embedded_test_server()->GetURL("/title1.html"),
1587 root->child_at(1)->current_url());
1589 // Update the second frame's sandbox flags.
1590 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1591 "window.domAutomationController.send("
1592 "document.querySelectorAll('iframe')[1].sandbox="
1593 "'allow-scripts');"));
1595 // Check that the current sandbox flags are updated but the effective
1596 // sandbox flags are not.
1597 SandboxFlags expected_flags = SandboxFlags::ALL & ~SandboxFlags::SCRIPTS &
1598 ~SandboxFlags::AUTOMATIC_FEATURES;
1599 EXPECT_EQ(expected_flags,
1600 root->child_at(1)->current_replication_state().sandbox_flags);
1601 EXPECT_EQ(SandboxFlags::NONE, root->child_at(1)->effective_sandbox_flags());
1603 // Navigate the second subframe to a page on bar.com. This will trigger a
1604 // remote-to-local frame swap in bar.com's process. The target page has
1605 // another frame, so use TestFrameNavigationObserver to wait for all frames
1606 // to be loaded.
1607 TestFrameNavigationObserver frame_observer(root->child_at(1), 2);
1608 GURL bar_url(embedded_test_server()->GetURL(
1609 "bar.com", "/frame_tree/page_with_one_frame.html"));
1610 NavigateFrameToURL(root->child_at(1), bar_url);
1611 frame_observer.Wait();
1612 EXPECT_EQ(bar_url, root->child_at(1)->current_url());
1613 ASSERT_EQ(1U, root->child_at(1)->child_count());
1615 // Confirm that the browser process has updated the current sandbox flags.
1616 EXPECT_EQ(expected_flags,
1617 root->child_at(1)->current_replication_state().sandbox_flags);
1618 EXPECT_EQ(expected_flags, root->child_at(1)->effective_sandbox_flags());
1620 // Opening a popup in the sandboxed second frame should fail.
1621 bool success = false;
1622 EXPECT_TRUE(
1623 ExecuteScriptAndExtractBool(root->child_at(1)->current_frame_host(),
1624 "window.domAutomationController.send("
1625 "!window.open('data:text/html,dataurl'));",
1626 &success));
1627 EXPECT_TRUE(success);
1628 EXPECT_EQ(1u, Shell::windows().size());
1630 // Make sure that the child frame inherits the sandbox flags of its
1631 // now-sandboxed parent frame.
1632 success = false;
1633 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1634 root->child_at(1)->child_at(0)->current_frame_host(),
1635 "window.domAutomationController.send("
1636 "!window.open('data:text/html,dataurl'));",
1637 &success));
1638 EXPECT_TRUE(success);
1639 EXPECT_EQ(1u, Shell::windows().size());
1642 // Check that dynamic updates to iframe sandbox flags are propagated correctly.
1643 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1644 DynamicSandboxFlagsRendererInitiatedNavigation) {
1645 GURL main_url(
1646 embedded_test_server()->GetURL("/frame_tree/page_with_one_frame.html"));
1647 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1649 // It is safe to obtain the root frame tree node here, as it doesn't change.
1650 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1651 ->GetFrameTree()
1652 ->root();
1654 TestNavigationObserver observer(shell()->web_contents());
1655 ASSERT_EQ(1U, root->child_count());
1657 // Make sure the frame starts out at the correct cross-site page.
1658 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title1.html"),
1659 root->child_at(0)->current_url());
1661 // The frame should not be sandboxed to start with.
1662 EXPECT_EQ(SandboxFlags::NONE,
1663 root->child_at(0)->current_replication_state().sandbox_flags);
1664 EXPECT_EQ(SandboxFlags::NONE, root->child_at(0)->effective_sandbox_flags());
1666 // Dynamically update the frame's sandbox flags.
1667 EXPECT_TRUE(ExecuteScript(shell()->web_contents(),
1668 "window.domAutomationController.send("
1669 "document.querySelector('iframe').sandbox="
1670 "'allow-scripts');"));
1672 // Check that updated sandbox flags are propagated to browser process.
1673 // The new flags should be set in current_replication_state(), while
1674 // effective_sandbox_flags() should still reflect the old flags, because
1675 // sandbox flag updates take place only after navigations. "allow-scripts"
1676 // resets both SandboxFlags::Scripts and SandboxFlags::AutomaticFeatures bits
1677 // per blink::parseSandboxPolicy().
1678 SandboxFlags expected_flags = SandboxFlags::ALL & ~SandboxFlags::SCRIPTS &
1679 ~SandboxFlags::AUTOMATIC_FEATURES;
1680 EXPECT_EQ(expected_flags,
1681 root->child_at(0)->current_replication_state().sandbox_flags);
1682 EXPECT_EQ(SandboxFlags::NONE, root->child_at(0)->effective_sandbox_flags());
1684 // Perform a renderer-initiated same-site navigation in the first frame. The
1685 // new sandbox flags should take effect.
1686 TestFrameNavigationObserver frame_observer(root->child_at(0));
1687 ASSERT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
1688 "window.location.href='/title2.html'"));
1689 frame_observer.Wait();
1690 EXPECT_EQ(embedded_test_server()->GetURL("baz.com", "/title2.html"),
1691 root->child_at(0)->current_url());
1693 // Confirm that the browser process has updated the frame's current sandbox
1694 // flags.
1695 EXPECT_EQ(expected_flags,
1696 root->child_at(0)->current_replication_state().sandbox_flags);
1697 EXPECT_EQ(expected_flags, root->child_at(0)->effective_sandbox_flags());
1699 // Opening a popup in the now-sandboxed frame should fail.
1700 bool success = false;
1701 EXPECT_TRUE(
1702 ExecuteScriptAndExtractBool(root->child_at(0)->current_frame_host(),
1703 "window.domAutomationController.send("
1704 "!window.open('data:text/html,dataurl'));",
1705 &success));
1706 EXPECT_TRUE(success);
1707 EXPECT_EQ(1u, Shell::windows().size());
1710 // Verify that a child frame can retrieve the name property set by its parent.
1711 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, WindowNameReplication) {
1712 GURL main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html"));
1713 EXPECT_TRUE(NavigateToURL(shell(), main_url));
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 TestNavigationObserver observer(shell()->web_contents());
1722 // Load cross-site page into iframe.
1723 GURL frame_url =
1724 embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html");
1725 NavigateFrameToURL(root->child_at(0), frame_url);
1726 EXPECT_TRUE(observer.last_navigation_succeeded());
1727 EXPECT_EQ(frame_url, observer.last_navigation_url());
1729 // Ensure that a new process is created for the subframe.
1730 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1731 root->child_at(0)->current_frame_host()->GetSiteInstance());
1733 // Check that the window.name seen by the frame matches the name attribute
1734 // specified by its parent in the iframe tag.
1735 std::string result;
1736 EXPECT_TRUE(ExecuteScriptAndExtractString(
1737 root->child_at(0)->current_frame_host(),
1738 "window.domAutomationController.send(window.name);", &result));
1739 EXPECT_EQ("3-1-name", result);
1742 // Verify that dynamic updates to a frame's window.name propagate to the
1743 // frame's proxies, so that the latest frame names can be used in navigations.
1744 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DynamicWindowName) {
1745 GURL main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html"));
1746 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1748 // It is safe to obtain the root frame tree node here, as it doesn't change.
1749 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1750 ->GetFrameTree()
1751 ->root();
1752 TestNavigationObserver observer(shell()->web_contents());
1754 // Load cross-site page into iframe.
1755 GURL frame_url =
1756 embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html");
1757 NavigateFrameToURL(root->child_at(0), frame_url);
1758 EXPECT_TRUE(observer.last_navigation_succeeded());
1759 EXPECT_EQ(frame_url, observer.last_navigation_url());
1761 // Browser process should know the child frame's original window.name
1762 // specified in the iframe element.
1763 EXPECT_EQ(root->child_at(0)->frame_name(), "3-1-name");
1765 // Update the child frame's window.name.
1766 EXPECT_TRUE(ExecuteScript(root->child_at(0)->current_frame_host(),
1767 "window.domAutomationController.send("
1768 "window.name = 'updated-name');"));
1770 // The change should propagate to the browser process.
1771 EXPECT_EQ(root->child_at(0)->frame_name(), "updated-name");
1773 // The proxy in the parent process should also receive the updated name.
1774 // Check that it can reference the child frame by its new name.
1775 bool success = false;
1776 EXPECT_TRUE(
1777 ExecuteScriptAndExtractBool(shell()->web_contents(),
1778 "window.domAutomationController.send("
1779 "frames['updated-name'] == frames[0]);",
1780 &success));
1781 EXPECT_TRUE(success);
1783 // Issue a renderer-initiated navigation from the root frame to the child
1784 // frame using the frame's name. Make sure correct frame is navigated.
1786 // TODO(alexmos): When blink::createWindow is refactored to handle
1787 // RemoteFrames, this should also be tested via window.open(url, frame_name)
1788 // and a more complicated frame hierarchy (https://crbug.com/463742)
1789 TestFrameNavigationObserver frame_observer(root->child_at(0));
1790 GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
1791 std::string script = base::StringPrintf(
1792 "window.domAutomationController.send("
1793 "frames['updated-name'].location.href = '%s');",
1794 foo_url.spec().c_str());
1795 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), script));
1796 frame_observer.Wait();
1797 EXPECT_EQ(foo_url, root->child_at(0)->current_url());
1800 // Ensure that navigating subframes in --site-per-process mode properly fires
1801 // the DidStopLoading event on WebContentsObserver.
1802 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteDidStopLoading) {
1803 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1804 NavigateToURL(shell(), main_url);
1806 // It is safe to obtain the root frame tree node here, as it doesn't change.
1807 FrameTreeNode* root =
1808 static_cast<WebContentsImpl*>(shell()->web_contents())->
1809 GetFrameTree()->root();
1811 TestNavigationObserver observer(shell()->web_contents());
1813 // Load same-site page into iframe.
1814 FrameTreeNode* child = root->child_at(0);
1815 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
1816 NavigateFrameToURL(child, http_url);
1817 EXPECT_EQ(http_url, observer.last_navigation_url());
1818 EXPECT_TRUE(observer.last_navigation_succeeded());
1820 // Load cross-site page into iframe.
1821 TestNavigationObserver nav_observer(shell()->web_contents(), 1);
1822 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
1823 NavigationController::LoadURLParams params(url);
1824 params.transition_type = ui::PAGE_TRANSITION_LINK;
1825 params.frame_tree_node_id = child->frame_tree_node_id();
1826 child->navigator()->GetController()->LoadURLWithParams(params);
1827 nav_observer.Wait();
1829 // Verify that the navigation succeeded and the expected URL was loaded.
1830 EXPECT_TRUE(observer.last_navigation_succeeded());
1831 EXPECT_EQ(url, observer.last_navigation_url());
1834 // Ensure that the renderer does not crash when navigating a frame that has a
1835 // sibling RemoteFrame. See https://crbug.com/426953.
1836 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1837 NavigateWithSiblingRemoteFrame) {
1838 GURL main_url(
1839 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
1840 NavigateToURL(shell(), main_url);
1842 // It is safe to obtain the root frame tree node here, as it doesn't change.
1843 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1844 ->GetFrameTree()
1845 ->root();
1846 TestNavigationObserver observer(shell()->web_contents());
1848 // Make sure the first frame is out of process.
1849 ASSERT_EQ(2U, root->child_count());
1850 FrameTreeNode* node2 = root->child_at(0);
1851 EXPECT_NE(root->current_frame_host()->GetSiteInstance(),
1852 node2->current_frame_host()->GetSiteInstance());
1854 // Make sure the second frame is in the parent's process.
1855 FrameTreeNode* node3 = root->child_at(1);
1856 EXPECT_EQ(root->current_frame_host()->GetSiteInstance(),
1857 node3->current_frame_host()->GetSiteInstance());
1859 // Navigate the second iframe (node3) to a URL in its own process.
1860 GURL title_url = embedded_test_server()->GetURL("/title2.html");
1861 NavigateFrameToURL(node3, title_url);
1862 EXPECT_TRUE(observer.last_navigation_succeeded());
1863 EXPECT_EQ(title_url, observer.last_navigation_url());
1864 EXPECT_EQ(root->current_frame_host()->GetSiteInstance(),
1865 node3->current_frame_host()->GetSiteInstance());
1866 EXPECT_TRUE(node3->current_frame_host()->IsRenderFrameLive());
1869 // Verify that load events for iframe elements work when the child frame is
1870 // out-of-process. In such cases, the load event is forwarded from the child
1871 // frame to the parent frame via the browser process.
1872 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, LoadEventForwarding) {
1873 // Load a page with a cross-site frame. The parent page has an onload
1874 // handler in the iframe element that appends "LOADED" to the document title.
1876 GURL main_url(
1877 embedded_test_server()->GetURL("/frame_with_load_event.html"));
1878 base::string16 expected_title(base::UTF8ToUTF16("LOADED"));
1879 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
1880 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1881 EXPECT_EQ(title_watcher.WaitAndGetTitle(), expected_title);
1884 // It is safe to obtain the root frame tree node here, as it doesn't change.
1885 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1886 ->GetFrameTree()
1887 ->root();
1889 // Load another cross-site page into the iframe and check that the load event
1890 // is fired.
1892 GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
1893 base::string16 expected_title(base::UTF8ToUTF16("LOADEDLOADED"));
1894 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
1895 TestNavigationObserver observer(shell()->web_contents());
1896 NavigateFrameToURL(root->child_at(0), foo_url);
1897 EXPECT_TRUE(observer.last_navigation_succeeded());
1898 EXPECT_EQ(foo_url, observer.last_navigation_url());
1899 EXPECT_EQ(title_watcher.WaitAndGetTitle(), expected_title);
1903 // Check that postMessage can be routed between cross-site iframes.
1904 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SubframePostMessage) {
1905 GURL main_url(embedded_test_server()->GetURL(
1906 "/frame_tree/page_with_post_message_frames.html"));
1907 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1909 // It is safe to obtain the root frame tree node here, as it doesn't change.
1910 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1911 ->GetFrameTree()
1912 ->root();
1914 TestNavigationObserver observer(shell()->web_contents());
1915 ASSERT_EQ(2U, root->child_count());
1917 // Verify the frames start at correct URLs. First frame should be
1918 // same-site; second frame should be cross-site.
1919 GURL same_site_url(embedded_test_server()->GetURL("/post_message.html"));
1920 EXPECT_EQ(same_site_url, root->child_at(0)->current_url());
1921 GURL foo_url(embedded_test_server()->GetURL("foo.com",
1922 "/post_message.html"));
1923 EXPECT_EQ(foo_url, root->child_at(1)->current_url());
1924 EXPECT_NE(root->child_at(0)->current_frame_host()->GetSiteInstance(),
1925 root->child_at(1)->current_frame_host()->GetSiteInstance());
1927 // Send a message from first, same-site frame to second, cross-site frame.
1928 // Expect the second frame to reply back to the first frame.
1930 // TODO(alexmos): Also try sending from second to first frame. Currently,
1931 // this fails due to https://crbug.com/473518, which prevents
1932 // parent.frames[x] from working when "parent" is a remote frame.
1933 bool success = false;
1934 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1935 root->child_at(0)->current_frame_host(),
1936 "window.domAutomationController.send("
1937 " postToSibling('subframe-msg','subframe2'));",
1938 &success));
1939 EXPECT_TRUE(success);
1941 // Wait for first frame to receive a reply from the second frame. It will
1942 // send "done-subframe1" from the DOMAutomationController when the reply
1943 // arrives.
1944 content::DOMMessageQueue msg_queue;
1945 std::string status;
1946 while (msg_queue.WaitForMessage(&status)) {
1947 if (status == "\"done-subframe1\"")
1948 break;
1951 // Send a postMessage from second, cross-site frame to its parent. Expect
1952 // parent to send a reply to the frame.
1953 base::string16 expected_title(base::ASCIIToUTF16("subframe-msg"));
1954 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
1955 success = false;
1956 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1957 root->child_at(1)->current_frame_host(),
1958 "window.domAutomationController.send(postToParent('subframe-msg'));",
1959 &success));
1960 EXPECT_TRUE(success);
1961 EXPECT_EQ(expected_title, title_watcher.WaitAndGetTitle());
1963 // Wait for second frame to receive a reply from the parent. The frame will
1964 // return "done-subframe2" from the DOMAutomationController when the reply
1965 // arrives.
1966 while (msg_queue.WaitForMessage(&status)) {
1967 if (status == "\"done-subframe2\"")
1968 break;
1971 // Verify the total number of received messages for each subframe. First
1972 // frame should have one message (reply from second frame), and second frame
1973 // should have two messages (message from first frame and reply from parent).
1974 int subframe1_received_messages = 0;
1975 int subframe2_received_messages = 0;
1976 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1977 root->child_at(0)->current_frame_host(),
1978 "window.domAutomationController.send(window.receivedMessages);",
1979 &subframe1_received_messages));
1980 EXPECT_EQ(1, subframe1_received_messages);
1981 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1982 root->child_at(1)->current_frame_host(),
1983 "window.domAutomationController.send(window.receivedMessages);",
1984 &subframe2_received_messages));
1985 EXPECT_EQ(2, subframe2_received_messages);
1988 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, RFPHDestruction) {
1989 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1990 NavigateToURL(shell(), main_url);
1992 // It is safe to obtain the root frame tree node here, as it doesn't change.
1993 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1994 ->GetFrameTree()
1995 ->root();
1997 TestNavigationObserver observer(shell()->web_contents());
1999 // Load cross-site page into iframe.
2000 FrameTreeNode* child = root->child_at(0);
2001 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
2002 NavigateFrameToURL(root->child_at(0), url);
2003 EXPECT_TRUE(observer.last_navigation_succeeded());
2004 EXPECT_EQ(url, observer.last_navigation_url());
2005 EXPECT_EQ(
2006 " Site A ------------ proxies for B\n"
2007 " |--Site B ------- proxies for A\n"
2008 " +--Site A ------- proxies for B\n"
2009 " |--Site A -- proxies for B\n"
2010 " +--Site A -- proxies for B\n"
2011 " +--Site A -- proxies for B\n"
2012 "Where A = http://127.0.0.1/\n"
2013 " B = http://foo.com/",
2014 DepictFrameTree(root));
2016 // Load another cross-site page.
2017 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
2018 NavigateIframeToURL(shell()->web_contents(), "test", url);
2019 EXPECT_TRUE(observer.last_navigation_succeeded());
2020 EXPECT_EQ(url, observer.last_navigation_url());
2021 EXPECT_EQ(
2022 " Site A ------------ proxies for C\n"
2023 " |--Site C ------- proxies for A\n"
2024 " +--Site A ------- proxies for C\n"
2025 " |--Site A -- proxies for C\n"
2026 " +--Site A -- proxies for C\n"
2027 " +--Site A -- proxies for C\n"
2028 "Where A = http://127.0.0.1/\n"
2029 " C = http://bar.com/",
2030 DepictFrameTree(root));
2032 // Navigate back to the parent's origin.
2033 url = embedded_test_server()->GetURL("/title1.html");
2034 NavigateFrameToURL(child, url);
2035 EXPECT_EQ(url, observer.last_navigation_url());
2036 EXPECT_TRUE(observer.last_navigation_succeeded());
2037 EXPECT_EQ(
2038 " Site A\n"
2039 " |--Site A\n"
2040 " +--Site A\n"
2041 " |--Site A\n"
2042 " +--Site A\n"
2043 " +--Site A\n"
2044 "Where A = http://127.0.0.1/",
2045 DepictFrameTree(root));
2048 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
2049 PageTransitionForSecondaryIframeNavigation) {
2050 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
2051 NavigateToURL(shell(), main_url);
2053 // It is safe to obtain the root frame tree node here, as it doesn't change.
2054 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
2055 ->GetFrameTree()
2056 ->root();
2058 TestNavigationObserver observer(shell()->web_contents());
2060 // Load same-site page into iframe.
2061 FrameTreeNode* child = root->child_at(0);
2062 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
2063 NavigateFrameToURL(child, http_url);
2064 EXPECT_EQ(http_url, observer.last_navigation_url());
2065 EXPECT_TRUE(observer.last_navigation_succeeded());
2067 // Load cross-site page into iframe.
2068 TestFrameNavigationObserver frame_observer(child, 1);
2069 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
2070 NavigateIframeToURL(shell()->web_contents(), "test", url);
2071 frame_observer.Wait();
2073 EXPECT_EQ(NAVIGATION_TYPE_NEW_SUBFRAME,
2074 frame_observer.load_committed_details().type);
2077 } // namespace content