ozone: evdev: Sync caps lock LED state to evdev
[chromium-blink-merge.git] / content / browser / site_per_process_browsertest.cc
blobf2a76b93138774dec32d1229c2dd83e4e48cae69
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 // Disabled for flaky crashing: crbug.com/446575
285 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
286 DISABLED_NavigateRemoteFrame) {
287 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
288 NavigateToURL(shell(), main_url);
290 // It is safe to obtain the root frame tree node here, as it doesn't change.
291 FrameTreeNode* root =
292 static_cast<WebContentsImpl*>(shell()->web_contents())->
293 GetFrameTree()->root();
295 TestNavigationObserver observer(shell()->web_contents());
297 // Load same-site page into iframe.
298 FrameTreeNode* child = root->child_at(0);
299 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
300 NavigateFrameToURL(child, http_url);
301 EXPECT_EQ(http_url, observer.last_navigation_url());
302 EXPECT_TRUE(observer.last_navigation_succeeded());
304 // Load cross-site page into iframe.
305 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
306 NavigateFrameToURL(root->child_at(0), url);
307 EXPECT_TRUE(observer.last_navigation_succeeded());
308 EXPECT_EQ(url, observer.last_navigation_url());
310 // Ensure that we have created a new process for the subframe.
311 ASSERT_EQ(2U, root->child_count());
312 SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
313 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
315 // Emulate the main frame changing the src of the iframe such that it
316 // navigates cross-site.
317 url = embedded_test_server()->GetURL("bar.com", "/title3.html");
318 NavigateIframeToURL(shell()->web_contents(), "test", url);
319 EXPECT_TRUE(observer.last_navigation_succeeded());
320 EXPECT_EQ(url, observer.last_navigation_url());
322 // Check again that a new process is created and is different from the
323 // top level one and the previous one.
324 ASSERT_EQ(2U, root->child_count());
325 child = root->child_at(0);
326 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
327 child->current_frame_host()->GetSiteInstance());
328 EXPECT_NE(site_instance,
329 child->current_frame_host()->GetSiteInstance());
331 // Navigate back to the parent's origin and ensure we return to the
332 // parent's process.
333 NavigateFrameToURL(child, http_url);
334 EXPECT_EQ(http_url, observer.last_navigation_url());
335 EXPECT_TRUE(observer.last_navigation_succeeded());
336 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
337 child->current_frame_host()->GetSiteInstance());
340 // This test checks that killing a renderer process of a remote frame
341 // and then navigating some other frame to the same SiteInstance of the killed
342 // process works properly.
343 // This can be illustrated as follows,
344 // where 1/2/3 are FrameTreeNode-s and A/B are processes and B* is the killed
345 // B process:
347 // 1 A A A
348 // / \ -> / \ -> Kill B -> / \ -> Navigate 3 to B -> / \ .
349 // 2 3 B A B* A B* B
351 // Initially, node1.proxy_hosts_ = {B}
352 // After we kill B, we make sure B stays in node1.proxy_hosts_, then we navigate
353 // 3 to B and we expect that to complete normally.
354 // See http://crbug.com/432107.
356 // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
357 // site B and stays in not rendered state.
358 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
359 NavigateRemoteFrameToKilledProcess) {
360 GURL main_url(embedded_test_server()->GetURL(
361 "/frame_tree/page_with_two_frames.html"));
362 NavigateToURL(shell(), main_url);
364 // It is safe to obtain the root frame tree node here, as it doesn't change.
365 FrameTreeNode* root =
366 static_cast<WebContentsImpl*>(shell()->web_contents())->
367 GetFrameTree()->root();
369 TestNavigationObserver observer(shell()->web_contents());
370 ASSERT_EQ(2U, root->child_count());
372 // Make sure node2 points to the correct cross-site page.
373 GURL site_b_url = embedded_test_server()->GetURL("bar.com", "/title1.html");
374 FrameTreeNode* node2 = root->child_at(0);
375 EXPECT_EQ(site_b_url, node2->current_url());
377 // Kill that cross-site renderer.
378 RenderProcessHost* child_process =
379 node2->current_frame_host()->GetProcess();
380 RenderProcessHostWatcher crash_observer(
381 child_process, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
382 child_process->Shutdown(0, false);
383 crash_observer.Wait();
385 // Now navigate the second iframe (node3) to the same site as the node2.
386 FrameTreeNode* node3 = root->child_at(1);
387 NavigateFrameToURL(node3, site_b_url);
388 EXPECT_TRUE(observer.last_navigation_succeeded());
389 EXPECT_EQ(site_b_url, observer.last_navigation_url());
392 // This test is similar to
393 // SitePerProcessBrowserTest.NavigateRemoteFrameToKilledProcess with
394 // addition that node2 also has a cross-origin frame to site C.
396 // 1 A A A
397 // / \ / \ / \ / \ .
398 // 2 3 -> B A -> Kill B -> B* A -> Navigate 3 -> B* B
399 // / /
400 // 4 C
402 // Initially, node1.proxy_hosts_ = {B, C}
403 // After we kill B, we make sure B stays in node1.proxy_hosts_, but
404 // C gets cleared from node1.proxy_hosts_.
406 // Note that due to http://crbug.com/450681, node2 cannot be re-navigated to
407 // site B and stays in not rendered state.
408 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
409 NavigateRemoteFrameToKilledProcessWithSubtree) {
410 GURL main_url(
411 embedded_test_server()->GetURL(
412 "/frame_tree/page_with_two_frames_nested.html"));
413 NavigateToURL(shell(), main_url);
415 // It is safe to obtain the root frame tree node here, as it doesn't change.
416 FrameTreeNode* root =
417 static_cast<WebContentsImpl*>(shell()->web_contents())->
418 GetFrameTree()->root();
419 TestNavigationObserver observer(shell()->web_contents());
421 ASSERT_EQ(2U, root->child_count());
423 GURL site_b_url(
424 embedded_test_server()->GetURL(
425 "bar.com", "/frame_tree/page_with_one_frame.html"));
426 // We can't use a TestNavigationObserver to verify the URL here,
427 // since the frame has children that may have clobbered it in the observer.
428 EXPECT_EQ(site_b_url, root->child_at(0)->current_url());
430 // Ensure that a new process is created for node2.
431 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
432 root->child_at(0)->current_frame_host()->GetSiteInstance());
433 // Ensure that a new process is *not* created for node3.
434 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
435 root->child_at(1)->current_frame_host()->GetSiteInstance());
437 ASSERT_EQ(1U, root->child_at(0)->child_count());
439 // Make sure node4 points to the correct cross-site page.
440 FrameTreeNode* node4 = root->child_at(0)->child_at(0);
441 GURL site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
442 EXPECT_EQ(site_c_url, node4->current_url());
444 // |site_instance_c| is expected to go away once we kill |child_process_b|
445 // below, so create a local scope so we can extend the lifetime of
446 // |site_instance_c| with a refptr.
448 SiteInstance* site_instance_b =
449 root->child_at(0)->current_frame_host()->GetSiteInstance();
450 // |site_c| will go away, so extend its lifetime with a refptr.
451 scoped_refptr<SiteInstanceImpl> site_instance_c =
452 node4->current_frame_host()->GetSiteInstance();
454 // Initially proxies for both B and C will be present in the root and node3.
455 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(
456 site_instance_b));
457 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(
458 site_instance_c.get()));
459 FrameTreeNode* node3 = root->child_at(1);
460 EXPECT_TRUE(node3->render_manager()->GetRenderFrameProxyHost(
461 site_instance_b));
462 EXPECT_TRUE(node3->render_manager()->GetRenderFrameProxyHost(
463 site_instance_c.get()));
465 // Kill that cross-site renderer/process B.
466 RenderProcessHost* child_process_b =
467 root->child_at(0)->current_frame_host()->GetProcess();
468 RenderProcessHostWatcher crash_observer(
469 child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
470 child_process_b->Shutdown(0, false);
471 crash_observer.Wait();
473 // Make sure proxy B stays around in root and node3.
474 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(
475 site_instance_b));
476 EXPECT_TRUE(node3->render_manager()->GetRenderFrameProxyHost(
477 site_instance_b));
478 // Make sure proxy C goes away from root and node3.
479 EXPECT_FALSE(root->render_manager()->GetRenderFrameProxyHost(
480 site_instance_c.get()));
481 EXPECT_FALSE(node3->render_manager()->GetRenderFrameProxyHost(
482 site_instance_c.get()));
485 // Now navigate the second iframe (node3) to the same site as the node2.
486 FrameTreeNode* node3 = root->child_at(1);
487 GURL url = embedded_test_server()->GetURL("bar.com", "/title1.html");
488 NavigateFrameToURL(node3, url);
489 EXPECT_TRUE(observer.last_navigation_succeeded());
490 EXPECT_EQ(url, observer.last_navigation_url());
493 // In A-embed-B-embed-C scenario, verify that killing process B clears proxies
494 // of C from the tree.
496 // 1 A A
497 // / \ / \ / \ .
498 // 2 3 -> B A -> Kill B -> B* A
499 // / /
500 // 4 C
502 // node1 is the root.
503 // Initially, both node1.proxy_hosts_ and node3.proxy_hosts_ contain C.
504 // After we kill B, make sure proxies for C are cleared.
505 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
506 KillingRendererClearsDescendantProxies) {
507 GURL main_url(
508 embedded_test_server()->GetURL(
509 "/frame_tree/page_with_two_frames_nested.html"));
510 NavigateToURL(shell(), main_url);
512 // It is safe to obtain the root frame tree node here, as it doesn't change.
513 FrameTreeNode* root =
514 static_cast<WebContentsImpl*>(shell()->web_contents())->
515 GetFrameTree()->root();
516 TestNavigationObserver observer(shell()->web_contents());
518 ASSERT_EQ(2U, root->child_count());
520 GURL site_b_url(
521 embedded_test_server()->GetURL(
522 "bar.com", "/frame_tree/page_with_one_frame.html"));
523 // We can't use a TestNavigationObserver to verify the URL here,
524 // since the frame has children that may have clobbered it in the observer.
525 EXPECT_EQ(site_b_url, root->child_at(0)->current_url());
527 // Ensure that a new process is created for node2.
528 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
529 root->child_at(0)->current_frame_host()->GetSiteInstance());
530 // Ensure that a new process is *not* created for node3.
531 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
532 root->child_at(1)->current_frame_host()->GetSiteInstance());
534 ASSERT_EQ(1U, root->child_at(0)->child_count());
536 // Make sure node4 points to the correct cross-site-page.
537 FrameTreeNode* node4 = root->child_at(0)->child_at(0);
538 GURL site_c_url(embedded_test_server()->GetURL("baz.com", "/title1.html"));
539 EXPECT_EQ(site_c_url, node4->current_url());
541 // |site_instance_c| is expected to go away once we kill |child_process_b|
542 // below, so create a local scope so we can extend the lifetime of
543 // |site_instance_c| with a refptr.
545 SiteInstance* site_instance_b =
546 root->child_at(0)->current_frame_host()->GetSiteInstance();
547 scoped_refptr<SiteInstanceImpl> site_instance_c =
548 node4->current_frame_host()->GetSiteInstance();
550 // Initially proxies for both B and C will be present in the root.
551 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(
552 site_instance_b));
553 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(
554 site_instance_c.get()));
556 // Kill process B.
557 RenderProcessHost* child_process_b =
558 root->child_at(0)->current_frame_host()->GetProcess();
559 RenderProcessHostWatcher crash_observer(
560 child_process_b, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
561 child_process_b->Shutdown(0, false);
562 crash_observer.Wait();
564 // Make sure proxy C has gone from root.
565 EXPECT_FALSE(root->render_manager()->GetRenderFrameProxyHost(
566 site_instance_c.get()));
567 // Make sure proxy C has gone from node3 as well.
568 EXPECT_FALSE(root->child_at(1)->render_manager()->GetRenderFrameProxyHost(
569 site_instance_c.get()));
570 // Make sure proxy B stays around in root and node3.
571 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(
572 site_instance_b));
573 EXPECT_TRUE(root->child_at(1)->render_manager()->GetRenderFrameProxyHost(
574 site_instance_b));
578 // Crash a subframe and ensures its children are cleared from the FrameTree.
579 // See http://crbug.com/338508.
580 // TODO(creis): Disabled for flakiness; see http://crbug.com/405582.
581 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DISABLED_CrashSubframe) {
582 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
583 NavigateToURL(shell(), main_url);
585 StartFrameAtDataURL();
587 // These must stay in scope with replace_host.
588 GURL::Replacements replace_host;
589 std::string foo_com("foo.com");
591 // Load cross-site page into iframe.
592 EXPECT_TRUE(NavigateIframeToURL(
593 shell()->web_contents(), "test",
594 embedded_test_server()->GetURL("/cross-site/foo.com/title2.html")));
596 // Check the subframe process.
597 FrameTreeNode* root =
598 static_cast<WebContentsImpl*>(shell()->web_contents())->
599 GetFrameTree()->root();
600 ASSERT_EQ(2U, root->child_count());
601 FrameTreeNode* child = root->child_at(0);
602 EXPECT_EQ(main_url, root->current_url());
603 EXPECT_EQ("foo.com", child->current_url().host());
604 EXPECT_EQ("/title2.html", child->current_url().path());
606 EXPECT_TRUE(
607 child->current_frame_host()->render_view_host()->IsRenderViewLive());
608 EXPECT_TRUE(child->current_frame_host()->IsRenderFrameLive());
610 // Crash the subframe process.
611 RenderProcessHost* root_process = root->current_frame_host()->GetProcess();
612 RenderProcessHost* child_process = child->current_frame_host()->GetProcess();
614 RenderProcessHostWatcher crash_observer(
615 child_process,
616 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
617 child_process->Shutdown(0, false);
618 crash_observer.Wait();
621 // Ensure that the child frame still exists but has been cleared.
622 EXPECT_EQ(2U, root->child_count());
623 EXPECT_EQ(main_url, root->current_url());
624 EXPECT_EQ(GURL(), child->current_url());
626 EXPECT_FALSE(
627 child->current_frame_host()->render_view_host()->IsRenderViewLive());
628 EXPECT_FALSE(child->current_frame_host()->IsRenderFrameLive());
629 EXPECT_FALSE(child->current_frame_host()->render_frame_created_);
631 // Now crash the top-level page to clear the child frame.
633 RenderProcessHostWatcher crash_observer(
634 root_process,
635 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
636 root_process->Shutdown(0, false);
637 crash_observer.Wait();
639 EXPECT_EQ(0U, root->child_count());
640 EXPECT_EQ(GURL(), root->current_url());
643 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
644 // security checks are back in place.
645 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
646 // on Android (http://crbug.com/187570).
647 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
648 DISABLED_CrossSiteIframeRedirectOnce) {
649 ASSERT_TRUE(test_server()->Start());
650 net::SpawnedTestServer https_server(
651 net::SpawnedTestServer::TYPE_HTTPS,
652 net::SpawnedTestServer::kLocalhost,
653 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
654 ASSERT_TRUE(https_server.Start());
656 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
657 GURL http_url(test_server()->GetURL("files/title1.html"));
658 GURL https_url(https_server.GetURL("files/title1.html"));
660 NavigateToURL(shell(), main_url);
662 TestNavigationObserver observer(shell()->web_contents());
664 // Load cross-site client-redirect page into Iframe.
665 // Should be blocked.
666 GURL client_redirect_https_url(https_server.GetURL(
667 "client-redirect?files/title1.html"));
668 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
669 client_redirect_https_url));
670 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
671 EXPECT_EQ(observer.last_navigation_url(), client_redirect_https_url);
672 EXPECT_FALSE(observer.last_navigation_succeeded());
676 // Load cross-site server-redirect page into Iframe,
677 // which redirects to same-site page.
678 GURL server_redirect_http_url(https_server.GetURL(
679 "server-redirect?" + http_url.spec()));
680 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
681 server_redirect_http_url));
682 EXPECT_EQ(observer.last_navigation_url(), http_url);
683 EXPECT_TRUE(observer.last_navigation_succeeded());
687 // Load cross-site server-redirect page into Iframe,
688 // which redirects to cross-site page.
689 GURL server_redirect_http_url(https_server.GetURL(
690 "server-redirect?files/title1.html"));
691 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
692 server_redirect_http_url));
693 // DidFailProvisionalLoad when navigating to https_url.
694 EXPECT_EQ(observer.last_navigation_url(), https_url);
695 EXPECT_FALSE(observer.last_navigation_succeeded());
699 // Load same-site server-redirect page into Iframe,
700 // which redirects to cross-site page.
701 GURL server_redirect_http_url(test_server()->GetURL(
702 "server-redirect?" + https_url.spec()));
703 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
704 server_redirect_http_url));
706 EXPECT_EQ(observer.last_navigation_url(), https_url);
707 EXPECT_FALSE(observer.last_navigation_succeeded());
711 // Load same-site client-redirect page into Iframe,
712 // which redirects to cross-site page.
713 GURL client_redirect_http_url(test_server()->GetURL(
714 "client-redirect?" + https_url.spec()));
716 RedirectNotificationObserver load_observer2(
717 NOTIFICATION_LOAD_STOP,
718 Source<NavigationController>(
719 &shell()->web_contents()->GetController()));
721 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
722 client_redirect_http_url));
724 // Same-site Client-Redirect Page should be loaded successfully.
725 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
726 EXPECT_TRUE(observer.last_navigation_succeeded());
728 // Redirecting to Cross-site Page should be blocked.
729 load_observer2.Wait();
730 EXPECT_EQ(observer.last_navigation_url(), https_url);
731 EXPECT_FALSE(observer.last_navigation_succeeded());
735 // Load same-site server-redirect page into Iframe,
736 // which redirects to same-site page.
737 GURL server_redirect_http_url(test_server()->GetURL(
738 "server-redirect?files/title1.html"));
739 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
740 server_redirect_http_url));
741 EXPECT_EQ(observer.last_navigation_url(), http_url);
742 EXPECT_TRUE(observer.last_navigation_succeeded());
746 // Load same-site client-redirect page into Iframe,
747 // which redirects to same-site page.
748 GURL client_redirect_http_url(test_server()->GetURL(
749 "client-redirect?" + http_url.spec()));
750 RedirectNotificationObserver load_observer2(
751 NOTIFICATION_LOAD_STOP,
752 Source<NavigationController>(
753 &shell()->web_contents()->GetController()));
755 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
756 client_redirect_http_url));
758 // Same-site Client-Redirect Page should be loaded successfully.
759 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
760 EXPECT_TRUE(observer.last_navigation_succeeded());
762 // Redirecting to Same-site Page should be loaded successfully.
763 load_observer2.Wait();
764 EXPECT_EQ(observer.last_navigation_url(), http_url);
765 EXPECT_TRUE(observer.last_navigation_succeeded());
769 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
770 // security checks are back in place.
771 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
772 // on Android (http://crbug.com/187570).
773 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
774 DISABLED_CrossSiteIframeRedirectTwice) {
775 ASSERT_TRUE(test_server()->Start());
776 net::SpawnedTestServer https_server(
777 net::SpawnedTestServer::TYPE_HTTPS,
778 net::SpawnedTestServer::kLocalhost,
779 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
780 ASSERT_TRUE(https_server.Start());
782 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
783 GURL http_url(test_server()->GetURL("files/title1.html"));
784 GURL https_url(https_server.GetURL("files/title1.html"));
786 NavigateToURL(shell(), main_url);
788 TestNavigationObserver observer(shell()->web_contents());
790 // Load client-redirect page pointing to a cross-site client-redirect page,
791 // which eventually redirects back to same-site page.
792 GURL client_redirect_https_url(https_server.GetURL(
793 "client-redirect?" + http_url.spec()));
794 GURL client_redirect_http_url(test_server()->GetURL(
795 "client-redirect?" + client_redirect_https_url.spec()));
797 // We should wait until second client redirect get cancelled.
798 RedirectNotificationObserver load_observer2(
799 NOTIFICATION_LOAD_STOP,
800 Source<NavigationController>(
801 &shell()->web_contents()->GetController()));
803 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
804 client_redirect_http_url));
806 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
807 load_observer2.Wait();
808 EXPECT_EQ(observer.last_navigation_url(), client_redirect_https_url);
809 EXPECT_FALSE(observer.last_navigation_succeeded());
813 // Load server-redirect page pointing to a cross-site server-redirect page,
814 // which eventually redirect back to same-site page.
815 GURL server_redirect_https_url(https_server.GetURL(
816 "server-redirect?" + http_url.spec()));
817 GURL server_redirect_http_url(test_server()->GetURL(
818 "server-redirect?" + server_redirect_https_url.spec()));
819 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
820 server_redirect_http_url));
821 EXPECT_EQ(observer.last_navigation_url(), http_url);
822 EXPECT_TRUE(observer.last_navigation_succeeded());
826 // Load server-redirect page pointing to a cross-site server-redirect page,
827 // which eventually redirects back to cross-site page.
828 GURL server_redirect_https_url(https_server.GetURL(
829 "server-redirect?" + https_url.spec()));
830 GURL server_redirect_http_url(test_server()->GetURL(
831 "server-redirect?" + server_redirect_https_url.spec()));
832 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
833 server_redirect_http_url));
835 // DidFailProvisionalLoad when navigating to https_url.
836 EXPECT_EQ(observer.last_navigation_url(), https_url);
837 EXPECT_FALSE(observer.last_navigation_succeeded());
841 // Load server-redirect page pointing to a cross-site client-redirect page,
842 // which eventually redirects back to same-site page.
843 GURL client_redirect_http_url(https_server.GetURL(
844 "client-redirect?" + http_url.spec()));
845 GURL server_redirect_http_url(test_server()->GetURL(
846 "server-redirect?" + client_redirect_http_url.spec()));
847 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
848 server_redirect_http_url));
850 // DidFailProvisionalLoad when navigating to client_redirect_http_url.
851 EXPECT_EQ(observer.last_navigation_url(), client_redirect_http_url);
852 EXPECT_FALSE(observer.last_navigation_succeeded());
856 // Ensure that when navigating a frame cross-process RenderFrameProxyHosts are
857 // created in the FrameTree skipping the subtree of the navigating frame.
859 // Disabled on Mac due to flakiness on ASAN. http://crbug.com/425248
860 // Disabled on Windows due to flakiness on Win 7 bot. http://crbug.com/444563
861 #if defined(OS_MACOSX) || defined(OS_WIN)
862 #define MAYBE_ProxyCreationSkipsSubtree DISABLED_ProxyCreationSkipsSubtree
863 #else
864 #define MAYBE_ProxyCreationSkipsSubtree ProxyCreationSkipsSubtree
865 #endif
866 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
867 MAYBE_ProxyCreationSkipsSubtree) {
868 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
869 NavigateToURL(shell(), main_url);
871 // It is safe to obtain the root frame tree node here, as it doesn't change.
872 FrameTreeNode* root =
873 static_cast<WebContentsImpl*>(shell()->web_contents())->
874 GetFrameTree()->root();
876 EXPECT_TRUE(root->child_at(1) != NULL);
877 EXPECT_EQ(2U, root->child_at(1)->child_count());
880 // Load same-site page into iframe.
881 TestNavigationObserver observer(shell()->web_contents());
882 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
883 NavigateFrameToURL(root->child_at(0), http_url);
884 EXPECT_EQ(http_url, observer.last_navigation_url());
885 EXPECT_TRUE(observer.last_navigation_succeeded());
886 RenderFrameProxyHost* proxy_to_parent =
887 root->child_at(0)->render_manager()->GetRenderFrameProxyHost(
888 shell()->web_contents()->GetSiteInstance());
889 EXPECT_FALSE(proxy_to_parent);
892 // Create the cross-site URL to navigate to.
893 GURL cross_site_url =
894 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html");
896 // Load cross-site page into the second iframe without waiting for the
897 // navigation to complete. Once LoadURLWithParams returns, we would expect
898 // proxies to have been created in the frame tree, but children of the
899 // navigating frame to still be present. The reason is that we don't run the
900 // message loop, so no IPCs that alter the frame tree can be processed.
901 FrameTreeNode* child = root->child_at(1);
902 SiteInstance* site = NULL;
904 TestNavigationObserver observer(shell()->web_contents());
905 TestFrameNavigationObserver navigation_observer(child);
906 NavigationController::LoadURLParams params(cross_site_url);
907 params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
908 params.frame_tree_node_id = child->frame_tree_node_id();
909 child->navigator()->GetController()->LoadURLWithParams(params);
910 EXPECT_TRUE(child->render_manager()->pending_frame_host());
912 site = child->render_manager()->pending_frame_host()->GetSiteInstance();
913 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site);
915 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(site));
916 EXPECT_TRUE(
917 root->child_at(0)->render_manager()->GetRenderFrameProxyHost(site));
918 EXPECT_FALSE(child->render_manager()->GetRenderFrameProxyHost(site));
919 for (size_t i = 0; i < child->child_count(); ++i) {
920 EXPECT_FALSE(
921 child->child_at(i)->render_manager()->GetRenderFrameProxyHost(site));
923 // Now that the verification is done, run the message loop and wait for the
924 // navigation to complete.
925 navigation_observer.Wait();
926 EXPECT_FALSE(child->render_manager()->pending_frame_host());
927 EXPECT_TRUE(observer.last_navigation_succeeded());
928 EXPECT_EQ(cross_site_url, observer.last_navigation_url());
931 // Load another cross-site page into the same iframe.
932 cross_site_url = embedded_test_server()->GetURL("bar.com", "/title2.html");
934 // Perform the same checks as the first cross-site navigation, since
935 // there have been issues in subsequent cross-site navigations. Also ensure
936 // that the SiteInstance has properly changed.
937 // TODO(nasko): Once we have proper cleanup of resources, add code to
938 // verify that the intermediate SiteInstance/RenderFrameHost have been
939 // properly cleaned up.
940 TestNavigationObserver observer(shell()->web_contents());
941 TestFrameNavigationObserver navigation_observer(child);
942 NavigationController::LoadURLParams params(cross_site_url);
943 params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
944 params.frame_tree_node_id = child->frame_tree_node_id();
945 child->navigator()->GetController()->LoadURLWithParams(params);
946 EXPECT_TRUE(child->render_manager()->pending_frame_host() != NULL);
948 SiteInstance* site2 =
949 child->render_manager()->pending_frame_host()->GetSiteInstance();
950 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site2);
951 EXPECT_NE(site, site2);
953 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(site2));
954 EXPECT_TRUE(
955 root->child_at(0)->render_manager()->GetRenderFrameProxyHost(site2));
956 EXPECT_FALSE(child->render_manager()->GetRenderFrameProxyHost(site2));
957 for (size_t i = 0; i < child->child_count(); ++i) {
958 EXPECT_FALSE(
959 child->child_at(i)->render_manager()->GetRenderFrameProxyHost(site2));
962 navigation_observer.Wait();
963 EXPECT_TRUE(observer.last_navigation_succeeded());
964 EXPECT_EQ(cross_site_url, observer.last_navigation_url());
965 EXPECT_EQ(0U, child->child_count());
969 // Verify that origin replication works for an A-embed-B-embed-C hierarchy.
970 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, OriginReplication) {
971 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
972 EXPECT_TRUE(NavigateToURL(shell(), main_url));
974 // It is safe to obtain the root frame tree node here, as it doesn't change.
975 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
976 ->GetFrameTree()
977 ->root();
979 TestNavigationObserver observer(shell()->web_contents());
981 // Navigate the first subframe to a cross-site page with two subframes.
982 // NavigateFrameToURL can't be used here because it doesn't guarantee that
983 // FrameTreeNodes will have been created for child frames when it returns.
984 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 4);
985 GURL foo_url(
986 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
987 NavigationController::LoadURLParams params(foo_url);
988 params.transition_type = ui::PAGE_TRANSITION_LINK;
989 params.frame_tree_node_id = root->child_at(0)->frame_tree_node_id();
990 root->child_at(0)->navigator()->GetController()->LoadURLWithParams(params);
991 frame_observer.Wait();
993 // We can't use a TestNavigationObserver to verify the URL here,
994 // since the frame has children that may have clobbered it in the observer.
995 EXPECT_EQ(foo_url, root->child_at(0)->current_url());
997 // Ensure that a new process is created for the subframe.
998 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
999 root->child_at(0)->current_frame_host()->GetSiteInstance());
1001 // Load cross-site page into subframe's subframe.
1002 ASSERT_EQ(2U, root->child_at(0)->child_count());
1003 GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
1004 NavigateFrameToURL(root->child_at(0)->child_at(0), bar_url);
1005 EXPECT_TRUE(observer.last_navigation_succeeded());
1006 EXPECT_EQ(bar_url, observer.last_navigation_url());
1008 // Check that a new process is created and is different from the top one and
1009 // the middle one.
1010 FrameTreeNode* bottom_child = root->child_at(0)->child_at(0);
1011 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1012 bottom_child->current_frame_host()->GetSiteInstance());
1013 EXPECT_NE(root->child_at(0)->current_frame_host()->GetSiteInstance(),
1014 bottom_child->current_frame_host()->GetSiteInstance());
1016 // Check that foo.com frame's location.ancestorOrigins contains the correct
1017 // origin for the parent. The origin should have been replicated as part of
1018 // the ViewMsg_New message that created the parent's RenderFrameProxy in
1019 // foo.com's process.
1020 int ancestor_origins_length = 0;
1021 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1022 root->child_at(0)->current_frame_host(),
1023 "window.domAutomationController.send(location.ancestorOrigins.length);",
1024 &ancestor_origins_length));
1025 EXPECT_EQ(1, ancestor_origins_length);
1026 std::string result;
1027 EXPECT_TRUE(ExecuteScriptAndExtractString(
1028 root->child_at(0)->current_frame_host(),
1029 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1030 &result));
1031 EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
1033 // Check that bar.com frame's location.ancestorOrigins contains the correct
1034 // origin for its two ancestors. The topmost parent origin should be
1035 // replicated as part of ViewMsg_New, and the middle frame (foo.com's) origin
1036 // should be replicated as part of FrameMsg_NewFrameProxy sent for foo.com's
1037 // frame in bar.com's process.
1038 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1039 bottom_child->current_frame_host(),
1040 "window.domAutomationController.send(location.ancestorOrigins.length);",
1041 &ancestor_origins_length));
1042 EXPECT_EQ(2, ancestor_origins_length);
1043 EXPECT_TRUE(ExecuteScriptAndExtractString(
1044 bottom_child->current_frame_host(),
1045 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1046 &result));
1047 EXPECT_EQ(result + "/", foo_url.GetOrigin().spec());
1048 EXPECT_TRUE(ExecuteScriptAndExtractString(
1049 bottom_child->current_frame_host(),
1050 "window.domAutomationController.send(location.ancestorOrigins[1]);",
1051 &result));
1052 EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
1055 // Check that iframe sandbox flags are replicated correctly.
1056 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, SandboxFlagsReplication) {
1057 GURL main_url(embedded_test_server()->GetURL("/sandboxed_frames.html"));
1058 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1060 // It is safe to obtain the root frame tree node here, as it doesn't change.
1061 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1062 ->GetFrameTree()
1063 ->root();
1065 TestNavigationObserver observer(shell()->web_contents());
1067 // Navigate the second (sandboxed) subframe to a cross-site page with a
1068 // subframe. Use RenderFrameHostCreatedObserver to guarantee that all
1069 // FrameTreeNodes are created for child frames.
1070 RenderFrameHostCreatedObserver frame_observer(shell()->web_contents(), 4);
1071 GURL foo_url(
1072 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
1073 NavigateFrameToURL(root->child_at(1), foo_url);
1074 frame_observer.Wait();
1076 // We can't use a TestNavigationObserver to verify the URL here,
1077 // since the frame has children that may have clobbered it in the observer.
1078 EXPECT_EQ(foo_url, root->child_at(1)->current_url());
1080 // Load cross-site page into subframe's subframe.
1081 ASSERT_EQ(2U, root->child_at(1)->child_count());
1082 GURL bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
1083 NavigateFrameToURL(root->child_at(1)->child_at(0), bar_url);
1084 EXPECT_TRUE(observer.last_navigation_succeeded());
1085 EXPECT_EQ(bar_url, observer.last_navigation_url());
1087 // Opening a popup in the sandboxed foo.com iframe should fail.
1088 bool success = false;
1089 EXPECT_TRUE(
1090 ExecuteScriptAndExtractBool(root->child_at(1)->current_frame_host(),
1091 "window.domAutomationController.send("
1092 "!window.open('data:text/html,dataurl'));",
1093 &success));
1094 EXPECT_TRUE(success);
1095 EXPECT_EQ(Shell::windows().size(), 1u);
1097 // Opening a popup in a frame whose parent is sandboxed should also fail.
1098 // Here, bar.com frame's sandboxed parent frame is a remote frame in
1099 // bar.com's process.
1100 success = false;
1101 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1102 root->child_at(1)->child_at(0)->current_frame_host(),
1103 "window.domAutomationController.send("
1104 "!window.open('data:text/html,dataurl'));",
1105 &success));
1106 EXPECT_TRUE(success);
1107 EXPECT_EQ(Shell::windows().size(), 1u);
1109 // Same, but now try the case where bar.com frame's sandboxed parent is a
1110 // local frame in bar.com's process.
1111 success = false;
1112 EXPECT_TRUE(ExecuteScriptAndExtractBool(
1113 root->child_at(2)->child_at(0)->current_frame_host(),
1114 "window.domAutomationController.send("
1115 "!window.open('data:text/html,dataurl'));",
1116 &success));
1117 EXPECT_TRUE(success);
1118 EXPECT_EQ(Shell::windows().size(), 1u);
1120 // Check that foo.com frame's location.ancestorOrigins contains the correct
1121 // origin for the parent, which should be unaffected by sandboxing.
1122 int ancestor_origins_length = 0;
1123 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1124 root->child_at(1)->current_frame_host(),
1125 "window.domAutomationController.send(location.ancestorOrigins.length);",
1126 &ancestor_origins_length));
1127 EXPECT_EQ(1, ancestor_origins_length);
1128 std::string result;
1129 EXPECT_TRUE(ExecuteScriptAndExtractString(
1130 root->child_at(1)->current_frame_host(),
1131 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1132 &result));
1133 EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
1135 // Now check location.ancestorOrigins for the bar.com frame. The middle frame
1136 // (foo.com's) origin should be unique, since that frame is sandboxed, and
1137 // the top frame should match |main_url|.
1138 FrameTreeNode* bottom_child = root->child_at(1)->child_at(0);
1139 EXPECT_TRUE(ExecuteScriptAndExtractInt(
1140 bottom_child->current_frame_host(),
1141 "window.domAutomationController.send(location.ancestorOrigins.length);",
1142 &ancestor_origins_length));
1143 EXPECT_EQ(2, ancestor_origins_length);
1144 EXPECT_TRUE(ExecuteScriptAndExtractString(
1145 bottom_child->current_frame_host(),
1146 "window.domAutomationController.send(location.ancestorOrigins[0]);",
1147 &result));
1148 EXPECT_EQ(result, "null");
1149 EXPECT_TRUE(ExecuteScriptAndExtractString(
1150 bottom_child->current_frame_host(),
1151 "window.domAutomationController.send(location.ancestorOrigins[1]);",
1152 &result));
1153 EXPECT_EQ(result + "/", main_url.GetOrigin().spec());
1156 // Verify that a child frame can retrieve the name property set by its parent.
1157 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, WindowNameReplication) {
1158 GURL main_url(embedded_test_server()->GetURL("/frame_tree/2-4.html"));
1159 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1161 // It is safe to obtain the root frame tree node here, as it doesn't change.
1162 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1163 ->GetFrameTree()
1164 ->root();
1166 TestNavigationObserver observer(shell()->web_contents());
1168 // Load cross-site page into iframe.
1169 GURL frame_url =
1170 embedded_test_server()->GetURL("foo.com", "/frame_tree/3-1.html");
1171 NavigateFrameToURL(root->child_at(0), frame_url);
1172 EXPECT_TRUE(observer.last_navigation_succeeded());
1173 EXPECT_EQ(frame_url, observer.last_navigation_url());
1175 // Ensure that a new process is created for the subframe.
1176 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1177 root->child_at(0)->current_frame_host()->GetSiteInstance());
1179 // Check that the window.name seen by the frame matches the name attribute
1180 // specified by its parent in the iframe tag.
1181 std::string result;
1182 EXPECT_TRUE(ExecuteScriptAndExtractString(
1183 root->child_at(0)->current_frame_host(),
1184 "window.domAutomationController.send(window.name);", &result));
1185 EXPECT_EQ(result, "3-1-name");
1188 // TODO(lfg): Merge the test below with NavigateRemoteFrame test.
1189 // TODO(lfg): Disabled because this triggers http://crbug.com/433012, and since
1190 // the renderer process crashes, it causes the title watcher to never return.
1191 // Alternatively, this could also be fixed if we could use NavigateIframeToURL
1192 // and classified the navigation as MANUAL_SUBFRAME (http://crbug.com/441863) or
1193 // if we waited for DidStopLoading (currently broken -- see comment in
1194 // NavigateIframeToURL).
1195 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1196 DISABLED_NavigateRemoteToDataURL) {
1197 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1198 NavigateToURL(shell(), main_url);
1200 // It is safe to obtain the root frame tree node here, as it doesn't change.
1201 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1202 ->GetFrameTree()
1203 ->root();
1205 TestNavigationObserver observer(shell()->web_contents());
1207 // Load cross-site page into iframe.
1208 GURL url = embedded_test_server()->GetURL("foo.com", "/title1.html");
1209 NavigateFrameToURL(root->child_at(0), url);
1210 EXPECT_TRUE(observer.last_navigation_succeeded());
1211 EXPECT_EQ(url, observer.last_navigation_url());
1213 // Ensure that we have created a new process for the subframe.
1214 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1215 root->child_at(0)->current_frame_host()->GetSiteInstance());
1217 // Navigate iframe to a data URL. The navigation happens from a script in the
1218 // parent frame, so the data URL should be committed in the same SiteInstance
1219 // as the parent frame.
1220 GURL data_url("data:text/html,dataurl");
1221 std::string script = base::StringPrintf(
1222 "setTimeout(function() {"
1223 "var iframe = document.getElementById('test');"
1224 "iframe.onload = function() { document.title = 'LOADED'; };"
1225 "iframe.src=\"%s\";"
1226 "},0);",
1227 data_url.spec().c_str());
1228 base::string16 passed_string(base::UTF8ToUTF16("LOADED"));
1229 TitleWatcher title_watcher(shell()->web_contents(), passed_string);
1230 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), script));
1231 EXPECT_EQ(title_watcher.WaitAndGetTitle(), passed_string);
1232 EXPECT_TRUE(observer.last_navigation_succeeded());
1233 EXPECT_EQ(data_url, observer.last_navigation_url());
1235 // Ensure that we have navigated using the top level process.
1236 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
1237 root->child_at(0)->current_frame_host()->GetSiteInstance());
1240 // TODO(lfg): Merge the test below with NavigateRemoteFrame test.
1241 // Disabled due to the same reason as NavigateRemoteToDataURL.
1242 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1243 DISABLED_NavigateRemoteToBlankURL) {
1244 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1245 NavigateToURL(shell(), main_url);
1247 // It is safe to obtain the root frame tree node here, as it doesn't change.
1248 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1249 ->GetFrameTree()
1250 ->root();
1252 TestNavigationObserver observer(shell()->web_contents());
1254 // Load cross-site page into iframe.
1255 GURL url = embedded_test_server()->GetURL("foo.com", "/title1.html");
1256 NavigateFrameToURL(root->child_at(0), url);
1257 EXPECT_TRUE(observer.last_navigation_succeeded());
1258 EXPECT_EQ(url, observer.last_navigation_url());
1260 // Ensure that we have created a new process for the subframe.
1261 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1262 root->child_at(0)->current_frame_host()->GetSiteInstance());
1264 // Navigate iframe to about:blank. The navigation happens from a script in the
1265 // parent frame, so it should be committed in the same SiteInstance as the
1266 // parent frame.
1267 GURL about_blank_url("about:blank");
1268 std::string script = base::StringPrintf(
1269 "setTimeout(function() {"
1270 "var iframe = document.getElementById('test');"
1271 "iframe.onload = function() { document.title = 'LOADED'; };"
1272 "iframe.src=\"%s\";"
1273 "},0);",
1274 about_blank_url.spec().c_str());
1275 base::string16 passed_string(base::UTF8ToUTF16("LOADED"));
1276 TitleWatcher title_watcher(shell()->web_contents(), passed_string);
1277 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), script));
1278 EXPECT_EQ(title_watcher.WaitAndGetTitle(), passed_string);
1279 EXPECT_TRUE(observer.last_navigation_succeeded());
1280 EXPECT_EQ(about_blank_url, observer.last_navigation_url());
1282 // Ensure that we have navigated using the top level process.
1283 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
1284 root->child_at(0)->current_frame_host()->GetSiteInstance());
1287 // Ensure that navigating subframes in --site-per-process mode properly fires
1288 // the DidStopLoading event on WebContentsObserver.
1289 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, CrossSiteDidStopLoading) {
1290 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1291 NavigateToURL(shell(), main_url);
1293 // It is safe to obtain the root frame tree node here, as it doesn't change.
1294 FrameTreeNode* root =
1295 static_cast<WebContentsImpl*>(shell()->web_contents())->
1296 GetFrameTree()->root();
1298 TestNavigationObserver observer(shell()->web_contents());
1300 // Load same-site page into iframe.
1301 FrameTreeNode* child = root->child_at(0);
1302 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
1303 NavigateFrameToURL(child, http_url);
1304 EXPECT_EQ(http_url, observer.last_navigation_url());
1305 EXPECT_TRUE(observer.last_navigation_succeeded());
1307 // Load cross-site page into iframe.
1308 TestNavigationObserver nav_observer(shell()->web_contents(), 1);
1309 GURL url = embedded_test_server()->GetURL("foo.com", "/title2.html");
1310 NavigationController::LoadURLParams params(url);
1311 params.transition_type = ui::PAGE_TRANSITION_LINK;
1312 params.frame_tree_node_id = child->frame_tree_node_id();
1313 child->navigator()->GetController()->LoadURLWithParams(params);
1314 nav_observer.Wait();
1316 // Verify that the navigation succeeded and the expected URL was loaded.
1317 EXPECT_TRUE(observer.last_navigation_succeeded());
1318 EXPECT_EQ(url, observer.last_navigation_url());
1321 // Ensure that the renderer does not crash when navigating a frame that has a
1322 // sibling RemoteFrame. See https://crbug.com/426953.
1323 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
1324 NavigateWithSiblingRemoteFrame) {
1325 GURL main_url(
1326 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
1327 NavigateToURL(shell(), main_url);
1329 // It is safe to obtain the root frame tree node here, as it doesn't change.
1330 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1331 ->GetFrameTree()
1332 ->root();
1333 TestNavigationObserver observer(shell()->web_contents());
1335 // Make sure the first frame is out of process.
1336 ASSERT_EQ(2U, root->child_count());
1337 FrameTreeNode* node2 = root->child_at(0);
1338 EXPECT_NE(root->current_frame_host()->GetSiteInstance(),
1339 node2->current_frame_host()->GetSiteInstance());
1341 // Make sure the second frame is in the parent's process.
1342 FrameTreeNode* node3 = root->child_at(1);
1343 EXPECT_EQ(root->current_frame_host()->GetSiteInstance(),
1344 node3->current_frame_host()->GetSiteInstance());
1346 // Navigate the second iframe (node3) to a URL in its own process.
1347 GURL title_url = embedded_test_server()->GetURL("/title2.html");
1348 NavigateFrameToURL(node3, title_url);
1349 EXPECT_TRUE(observer.last_navigation_succeeded());
1350 EXPECT_EQ(title_url, observer.last_navigation_url());
1351 EXPECT_EQ(root->current_frame_host()->GetSiteInstance(),
1352 node3->current_frame_host()->GetSiteInstance());
1353 EXPECT_TRUE(node3->current_frame_host()->IsRenderFrameLive());
1356 // Verify that load events for iframe elements work when the child frame is
1357 // out-of-process. In such cases, the load event is forwarded from the child
1358 // frame to the parent frame via the browser process.
1359 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, LoadEventForwarding) {
1360 // Load a page with a cross-site frame. The parent page has an onload
1361 // handler in the iframe element that appends "LOADED" to the document title.
1363 GURL main_url(
1364 embedded_test_server()->GetURL("/frame_with_load_event.html"));
1365 base::string16 expected_title(base::UTF8ToUTF16("LOADED"));
1366 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
1367 EXPECT_TRUE(NavigateToURL(shell(), main_url));
1368 EXPECT_EQ(title_watcher.WaitAndGetTitle(), expected_title);
1371 // It is safe to obtain the root frame tree node here, as it doesn't change.
1372 FrameTreeNode* root = static_cast<WebContentsImpl*>(shell()->web_contents())
1373 ->GetFrameTree()
1374 ->root();
1376 // Load another cross-site page into the iframe and check that the load event
1377 // is fired.
1379 GURL foo_url(embedded_test_server()->GetURL("foo.com", "/title1.html"));
1380 base::string16 expected_title(base::UTF8ToUTF16("LOADEDLOADED"));
1381 TitleWatcher title_watcher(shell()->web_contents(), expected_title);
1382 TestNavigationObserver observer(shell()->web_contents());
1383 NavigateFrameToURL(root->child_at(0), foo_url);
1384 EXPECT_TRUE(observer.last_navigation_succeeded());
1385 EXPECT_EQ(foo_url, observer.last_navigation_url());
1386 EXPECT_EQ(title_watcher.WaitAndGetTitle(), expected_title);
1390 } // namespace content