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/browser/web_contents_observer.h"
21 #include "content/public/common/content_switches.h"
22 #include "content/public/test/browser_test_utils.h"
23 #include "content/public/test/content_browser_test_utils.h"
24 #include "content/public/test/test_navigation_observer.h"
25 #include "content/public/test/test_utils.h"
26 #include "content/shell/browser/shell.h"
27 #include "content/test/content_browser_test_utils_internal.h"
28 #include "content/test/test_frame_navigation_observer.h"
29 #include "net/dns/mock_host_resolver.h"
30 #include "net/test/embedded_test_server/embedded_test_server.h"
34 class SitePerProcessWebContentsObserver
: public WebContentsObserver
{
36 explicit SitePerProcessWebContentsObserver(WebContents
* web_contents
)
37 : WebContentsObserver(web_contents
),
38 navigation_succeeded_(false) {}
39 ~SitePerProcessWebContentsObserver() override
{}
41 void DidStartProvisionalLoadForFrame(RenderFrameHost
* render_frame_host
,
42 const GURL
& validated_url
,
44 bool is_iframe_srcdoc
) override
{
45 navigation_succeeded_
= false;
48 void DidFailProvisionalLoad(
49 RenderFrameHost
* render_frame_host
,
50 const GURL
& validated_url
,
52 const base::string16
& error_description
) override
{
53 navigation_url_
= validated_url
;
54 navigation_succeeded_
= false;
57 void DidCommitProvisionalLoadForFrame(
58 RenderFrameHost
* render_frame_host
,
60 ui::PageTransition transition_type
) override
{
61 navigation_url_
= url
;
62 navigation_succeeded_
= true;
65 const GURL
& navigation_url() const {
66 return navigation_url_
;
69 int navigation_succeeded() const { return navigation_succeeded_
; }
73 bool navigation_succeeded_
;
75 DISALLOW_COPY_AND_ASSIGN(SitePerProcessWebContentsObserver
);
78 class RedirectNotificationObserver
: public NotificationObserver
{
80 // Register to listen for notifications of the given type from either a
81 // specific source, or from all sources if |source| is
82 // NotificationService::AllSources().
83 RedirectNotificationObserver(int notification_type
,
84 const NotificationSource
& source
);
85 ~RedirectNotificationObserver() override
;
87 // Wait until the specified notification occurs. If the notification was
88 // emitted between the construction of this object and this call then it
89 // returns immediately.
92 // Returns NotificationService::AllSources() if we haven't observed a
94 const NotificationSource
& source() const {
98 const NotificationDetails
& details() const {
102 // NotificationObserver:
103 void Observe(int type
,
104 const NotificationSource
& source
,
105 const NotificationDetails
& details
) override
;
111 NotificationRegistrar registrar_
;
113 NotificationSource source_
;
114 NotificationDetails details_
;
115 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
117 DISALLOW_COPY_AND_ASSIGN(RedirectNotificationObserver
);
120 RedirectNotificationObserver::RedirectNotificationObserver(
121 int notification_type
,
122 const NotificationSource
& source
)
125 source_(NotificationService::AllSources()) {
126 registrar_
.Add(this, notification_type
, source
);
129 RedirectNotificationObserver::~RedirectNotificationObserver() {}
131 void RedirectNotificationObserver::Wait() {
132 if (seen_
&& seen_twice_
)
136 message_loop_runner_
= new MessageLoopRunner
;
137 message_loop_runner_
->Run();
141 void RedirectNotificationObserver::Observe(
143 const NotificationSource
& source
,
144 const NotificationDetails
& details
) {
152 message_loop_runner_
->Quit();
156 // This observer keeps track of the number of created RenderFrameHosts. Tests
157 // can use this to ensure that a certain number of child frames has been
158 // created after navigating.
159 class RenderFrameHostCreatedObserver
: public WebContentsObserver
{
161 RenderFrameHostCreatedObserver(WebContents
* web_contents
,
162 int expected_frame_count
)
163 : WebContentsObserver(web_contents
),
164 expected_frame_count_(expected_frame_count
),
166 message_loop_runner_(new MessageLoopRunner
) {}
168 ~RenderFrameHostCreatedObserver() override
;
170 // Runs a nested message loop and blocks until the expected number of
171 // RenderFrameHosts is created.
175 // WebContentsObserver
176 void RenderFrameCreated(RenderFrameHost
* render_frame_host
) override
;
178 // The number of RenderFrameHosts to wait for.
179 int expected_frame_count_
;
181 // The number of RenderFrameHosts that have been created.
184 // The MessageLoopRunner used to spin the message loop.
185 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
187 DISALLOW_COPY_AND_ASSIGN(RenderFrameHostCreatedObserver
);
190 RenderFrameHostCreatedObserver::~RenderFrameHostCreatedObserver() {
193 void RenderFrameHostCreatedObserver::Wait() {
194 message_loop_runner_
->Run();
197 void RenderFrameHostCreatedObserver::RenderFrameCreated(
198 RenderFrameHost
* render_frame_host
) {
200 if (frames_created_
== expected_frame_count_
) {
201 message_loop_runner_
->Quit();
206 // SitePerProcessBrowserTest
209 SitePerProcessBrowserTest::SitePerProcessBrowserTest() {
212 void SitePerProcessBrowserTest::StartFrameAtDataURL() {
213 std::string data_url_script
=
214 "var iframes = document.getElementById('test');iframes.src="
215 "'data:text/html,dataurl';";
216 ASSERT_TRUE(ExecuteScript(shell()->web_contents(), data_url_script
));
219 void SitePerProcessBrowserTest::SetUpCommandLine(
220 base::CommandLine
* command_line
) {
221 command_line
->AppendSwitch(switches::kSitePerProcess
);
224 void SitePerProcessBrowserTest::SetUpOnMainThread() {
225 host_resolver()->AddRule("*", "127.0.0.1");
226 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
227 SetupCrossSiteRedirector(embedded_test_server());
230 // Ensure that navigating subframes in --site-per-process mode works and the
231 // correct documents are committed.
232 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, CrossSiteIframe
) {
233 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
234 NavigateToURL(shell(), main_url
);
236 // It is safe to obtain the root frame tree node here, as it doesn't change.
237 FrameTreeNode
* root
=
238 static_cast<WebContentsImpl
*>(shell()->web_contents())->
239 GetFrameTree()->root();
241 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
243 // Load same-site page into iframe.
244 FrameTreeNode
* child
= root
->child_at(0);
245 GURL
http_url(embedded_test_server()->GetURL("/title1.html"));
246 NavigateFrameToURL(child
, http_url
);
247 EXPECT_EQ(http_url
, observer
.navigation_url());
248 EXPECT_TRUE(observer
.navigation_succeeded());
250 // There should be only one RenderWidgetHost when there are no
251 // cross-process iframes.
252 std::set
<RenderWidgetHostView
*> views_set
=
253 static_cast<WebContentsImpl
*>(shell()->web_contents())
254 ->GetRenderWidgetHostViewsInTree();
255 EXPECT_EQ(1U, views_set
.size());
257 RenderFrameProxyHost
* proxy_to_parent
=
258 child
->render_manager()->GetRenderFrameProxyHost(
259 shell()->web_contents()->GetSiteInstance());
260 EXPECT_FALSE(proxy_to_parent
);
262 // Load cross-site page into iframe.
263 GURL url
= embedded_test_server()->GetURL("foo.com", "/title2.html");
264 NavigateFrameToURL(root
->child_at(0), url
);
265 // Verify that the navigation succeeded and the expected URL was loaded.
266 EXPECT_TRUE(observer
.navigation_succeeded());
267 EXPECT_EQ(url
, observer
.navigation_url());
269 // Ensure that we have created a new process for the subframe.
270 ASSERT_EQ(2U, root
->child_count());
271 SiteInstance
* site_instance
= child
->current_frame_host()->GetSiteInstance();
272 RenderViewHost
* rvh
= child
->current_frame_host()->render_view_host();
273 RenderProcessHost
* rph
= child
->current_frame_host()->GetProcess();
274 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh
);
275 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance
);
276 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), rph
);
278 // There should be now two RenderWidgetHosts, one for each process
279 // rendering a frame.
280 std::set
<RenderWidgetHostView
*> views_set
=
281 static_cast<WebContentsImpl
*>(shell()->web_contents())
282 ->GetRenderWidgetHostViewsInTree();
283 EXPECT_EQ(2U, views_set
.size());
285 proxy_to_parent
= child
->render_manager()->GetProxyToParent();
286 EXPECT_TRUE(proxy_to_parent
);
287 EXPECT_TRUE(proxy_to_parent
->cross_process_frame_connector());
290 proxy_to_parent
->cross_process_frame_connector()->get_view_for_testing());
292 // Load another cross-site page into the same iframe.
293 url
= embedded_test_server()->GetURL("bar.com", "/title3.html");
294 NavigateFrameToURL(root
->child_at(0), url
);
295 EXPECT_TRUE(observer
.navigation_succeeded());
296 EXPECT_EQ(url
, observer
.navigation_url());
298 // Check again that a new process is created and is different from the
299 // top level one and the previous one.
300 ASSERT_EQ(2U, root
->child_count());
301 child
= root
->child_at(0);
302 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(),
303 child
->current_frame_host()->render_view_host());
304 EXPECT_NE(rvh
, child
->current_frame_host()->render_view_host());
305 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
306 child
->current_frame_host()->GetSiteInstance());
307 EXPECT_NE(site_instance
,
308 child
->current_frame_host()->GetSiteInstance());
309 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(),
310 child
->current_frame_host()->GetProcess());
311 EXPECT_NE(rph
, child
->current_frame_host()->GetProcess());
313 std::set
<RenderWidgetHostView
*> views_set
=
314 static_cast<WebContentsImpl
*>(shell()->web_contents())
315 ->GetRenderWidgetHostViewsInTree();
316 EXPECT_EQ(2U, views_set
.size());
318 EXPECT_EQ(proxy_to_parent
, child
->render_manager()->GetProxyToParent());
319 EXPECT_TRUE(proxy_to_parent
->cross_process_frame_connector());
321 child
->current_frame_host()->render_view_host()->GetView(),
322 proxy_to_parent
->cross_process_frame_connector()->get_view_for_testing());
325 // Disabled for flaky crashing: crbug.com/446575
326 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
327 DISABLED_NavigateRemoteFrame
) {
328 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
329 NavigateToURL(shell(), main_url
);
331 // It is safe to obtain the root frame tree node here, as it doesn't change.
332 FrameTreeNode
* root
=
333 static_cast<WebContentsImpl
*>(shell()->web_contents())->
334 GetFrameTree()->root();
336 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
338 // Load same-site page into iframe.
339 FrameTreeNode
* child
= root
->child_at(0);
340 GURL
http_url(embedded_test_server()->GetURL("/title1.html"));
341 NavigateFrameToURL(child
, http_url
);
342 EXPECT_EQ(http_url
, observer
.navigation_url());
343 EXPECT_TRUE(observer
.navigation_succeeded());
345 // Load cross-site page into iframe.
346 GURL url
= embedded_test_server()->GetURL("foo.com", "/title2.html");
347 NavigateFrameToURL(root
->child_at(0), url
);
348 EXPECT_TRUE(observer
.navigation_succeeded());
349 EXPECT_EQ(url
, observer
.navigation_url());
351 // Ensure that we have created a new process for the subframe.
352 ASSERT_EQ(2U, root
->child_count());
353 SiteInstance
* site_instance
= child
->current_frame_host()->GetSiteInstance();
354 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance
);
356 // Emulate the main frame changing the src of the iframe such that it
357 // navigates cross-site.
358 url
= embedded_test_server()->GetURL("bar.com", "/title3.html");
359 NavigateIframeToURL(shell()->web_contents(), "test", url
);
360 EXPECT_TRUE(observer
.navigation_succeeded());
361 EXPECT_EQ(url
, observer
.navigation_url());
363 // Check again that a new process is created and is different from the
364 // top level one and the previous one.
365 ASSERT_EQ(2U, root
->child_count());
366 child
= root
->child_at(0);
367 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
368 child
->current_frame_host()->GetSiteInstance());
369 EXPECT_NE(site_instance
,
370 child
->current_frame_host()->GetSiteInstance());
372 // Navigate back to the parent's origin and ensure we return to the
374 NavigateFrameToURL(child
, http_url
);
375 EXPECT_EQ(http_url
, observer
.navigation_url());
376 EXPECT_TRUE(observer
.navigation_succeeded());
377 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
378 child
->current_frame_host()->GetSiteInstance());
381 // In A-embed-B-embed-C scenario, verify that killing process B clears proxies
382 // of C from the tree.
386 // 2 3 -> B A -> Kill B -> B* A
390 // node1 is the root.
391 // Initially, both node1.proxy_hosts_ and node3.proxy_hosts_ contain C.
392 // After we kill B, make sure proxies for C are cleared.
394 // TODO(lazyboy): Once http://crbug.com/432107 is fixed, we should also make
395 // sure that proxies for B are not cleared when we kill B.
396 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
397 KillingRendererClearsDescendantProxies
) {
399 embedded_test_server()->GetURL("/frame_tree/page_with_two_frames.html"));
400 NavigateToURL(shell(), main_url
);
402 // It is safe to obtain the root frame tree node here, as it doesn't change.
403 FrameTreeNode
* root
=
404 static_cast<WebContentsImpl
*>(shell()->web_contents())->
405 GetFrameTree()->root();
406 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
408 ASSERT_EQ(2U, root
->child_count());
410 // Navigate the second subframe (node3) to a local frame.
411 GURL
site_a_url(embedded_test_server()->GetURL("/title1.html"));
412 NavigateFrameToURL(root
->child_at(1), site_a_url
);
414 // Navigate the first subframe (node2) to a cross-site page with two
416 // NavigateFrameToURL can't be used here because it doesn't guarantee that
417 // FrameTreeNodes will have been created for child frames when it returns.
418 RenderFrameHostCreatedObserver
frame_observer(shell()->web_contents(), 3);
420 embedded_test_server()->GetURL(
421 "bar.com", "/frame_tree/page_with_one_frame.html"));
422 NavigationController::LoadURLParams
params_b(site_b_url
);
423 params_b
.transition_type
= ui::PAGE_TRANSITION_LINK
;
424 params_b
.frame_tree_node_id
= root
->child_at(0)->frame_tree_node_id();
425 root
->child_at(0)->navigator()->GetController()->LoadURLWithParams(params_b
);
426 frame_observer
.Wait();
428 // We can't use a SitePerProcessWebContentsObserver to verify the URL here,
429 // since the frame has children that may have clobbered it in the observer.
430 EXPECT_EQ(site_b_url
, root
->child_at(0)->current_url());
432 // Ensure that a new process is created for node2.
433 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
434 root
->child_at(0)->current_frame_host()->GetSiteInstance());
435 // Ensure that a new process is *not* created for node3.
436 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
437 root
->child_at(1)->current_frame_host()->GetSiteInstance());
439 ASSERT_EQ(1U, root
->child_at(0)->child_count());
441 // Navigate node4 to cross-site-page.
442 FrameTreeNode
* node4
= root
->child_at(0)->child_at(0);
443 GURL
site_c_url(embedded_test_server()->GetURL("baz.com", "/title2.html"));
444 NavigateFrameToURL(node4
, site_c_url
);
445 EXPECT_TRUE(observer
.navigation_succeeded());
446 EXPECT_EQ(site_c_url
, observer
.navigation_url());
448 // |site_instance_c| is expected to go away once we kill |child_process_b|
449 // below, so create a local scope so we can extend the lifetime of
450 // |site_instance_c| with a refptr.
452 SiteInstance
* site_instance_b
=
453 root
->child_at(0)->current_frame_host()->GetSiteInstance();
454 scoped_refptr
<SiteInstanceImpl
> site_instance_c
=
455 node4
->current_frame_host()->GetSiteInstance();
457 // Initially proxies for both B and C will be present in the root.
458 EXPECT_TRUE(root
->render_manager()->GetRenderFrameProxyHost(
460 EXPECT_TRUE(root
->render_manager()->GetRenderFrameProxyHost(
461 site_instance_c
.get()));
464 RenderProcessHost
* child_process_b
=
465 root
->child_at(0)->current_frame_host()->GetProcess();
466 RenderProcessHostWatcher
crash_observer(
467 child_process_b
, RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
468 child_process_b
->Shutdown(0, false);
469 crash_observer
.Wait();
471 // Make sure proxy C has gone from root.
472 EXPECT_FALSE(root
->render_manager()->GetRenderFrameProxyHost(
473 site_instance_c
.get()));
474 // Make sure proxy C has gone from node3 as well.
475 EXPECT_FALSE(root
->child_at(1)->render_manager()->GetRenderFrameProxyHost(
476 site_instance_c
.get()));
477 // TODO(lazyboy): Once http://crbug.com/432107 is fixed, we should also
478 // check that proxy B exists in both root and node3.
482 // Crash a subframe and ensures its children are cleared from the FrameTree.
483 // See http://crbug.com/338508.
484 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, CrashSubframe
) {
485 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
486 NavigateToURL(shell(), main_url
);
488 StartFrameAtDataURL();
490 // These must stay in scope with replace_host.
491 GURL::Replacements replace_host
;
492 std::string
foo_com("foo.com");
494 // Load cross-site page into iframe.
495 EXPECT_TRUE(NavigateIframeToURL(
496 shell()->web_contents(), "test",
497 embedded_test_server()->GetURL("/cross-site/foo.com/title2.html")));
499 // Check the subframe process.
500 FrameTreeNode
* root
=
501 static_cast<WebContentsImpl
*>(shell()->web_contents())->
502 GetFrameTree()->root();
503 ASSERT_EQ(2U, root
->child_count());
504 FrameTreeNode
* child
= root
->child_at(0);
505 EXPECT_EQ(main_url
, root
->current_url());
506 EXPECT_EQ("foo.com", child
->current_url().host());
507 EXPECT_EQ("/title2.html", child
->current_url().path());
510 child
->current_frame_host()->render_view_host()->IsRenderViewLive());
511 EXPECT_TRUE(child
->current_frame_host()->IsRenderFrameLive());
513 // Crash the subframe process.
514 RenderProcessHost
* root_process
= root
->current_frame_host()->GetProcess();
515 RenderProcessHost
* child_process
= child
->current_frame_host()->GetProcess();
517 RenderProcessHostWatcher
crash_observer(
519 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
520 child_process
->Shutdown(0, false);
521 crash_observer
.Wait();
524 // Ensure that the child frame still exists but has been cleared.
525 EXPECT_EQ(2U, root
->child_count());
526 EXPECT_EQ(main_url
, root
->current_url());
527 EXPECT_EQ(GURL(), child
->current_url());
530 child
->current_frame_host()->render_view_host()->IsRenderViewLive());
531 EXPECT_FALSE(child
->current_frame_host()->IsRenderFrameLive());
532 EXPECT_FALSE(child
->current_frame_host()->render_frame_created_
);
534 // Now crash the top-level page to clear the child frame.
536 RenderProcessHostWatcher
crash_observer(
538 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
539 root_process
->Shutdown(0, false);
540 crash_observer
.Wait();
542 EXPECT_EQ(0U, root
->child_count());
543 EXPECT_EQ(GURL(), root
->current_url());
546 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
547 // security checks are back in place.
548 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
549 // on Android (http://crbug.com/187570).
550 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
551 DISABLED_CrossSiteIframeRedirectOnce
) {
552 ASSERT_TRUE(test_server()->Start());
553 net::SpawnedTestServer
https_server(
554 net::SpawnedTestServer::TYPE_HTTPS
,
555 net::SpawnedTestServer::kLocalhost
,
556 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
557 ASSERT_TRUE(https_server
.Start());
559 GURL
main_url(test_server()->GetURL("files/site_per_process_main.html"));
560 GURL
http_url(test_server()->GetURL("files/title1.html"));
561 GURL
https_url(https_server
.GetURL("files/title1.html"));
563 NavigateToURL(shell(), main_url
);
565 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
567 // Load cross-site client-redirect page into Iframe.
568 // Should be blocked.
569 GURL
client_redirect_https_url(https_server
.GetURL(
570 "client-redirect?files/title1.html"));
571 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
572 client_redirect_https_url
));
573 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
574 EXPECT_EQ(observer
.navigation_url(), client_redirect_https_url
);
575 EXPECT_FALSE(observer
.navigation_succeeded());
579 // Load cross-site server-redirect page into Iframe,
580 // which redirects to same-site page.
581 GURL
server_redirect_http_url(https_server
.GetURL(
582 "server-redirect?" + http_url
.spec()));
583 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
584 server_redirect_http_url
));
585 EXPECT_EQ(observer
.navigation_url(), http_url
);
586 EXPECT_TRUE(observer
.navigation_succeeded());
590 // Load cross-site server-redirect page into Iframe,
591 // which redirects to cross-site page.
592 GURL
server_redirect_http_url(https_server
.GetURL(
593 "server-redirect?files/title1.html"));
594 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
595 server_redirect_http_url
));
596 // DidFailProvisionalLoad when navigating to https_url.
597 EXPECT_EQ(observer
.navigation_url(), https_url
);
598 EXPECT_FALSE(observer
.navigation_succeeded());
602 // Load same-site server-redirect page into Iframe,
603 // which redirects to cross-site page.
604 GURL
server_redirect_http_url(test_server()->GetURL(
605 "server-redirect?" + https_url
.spec()));
606 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
607 server_redirect_http_url
));
609 EXPECT_EQ(observer
.navigation_url(), https_url
);
610 EXPECT_FALSE(observer
.navigation_succeeded());
614 // Load same-site client-redirect page into Iframe,
615 // which redirects to cross-site page.
616 GURL
client_redirect_http_url(test_server()->GetURL(
617 "client-redirect?" + https_url
.spec()));
619 RedirectNotificationObserver
load_observer2(
620 NOTIFICATION_LOAD_STOP
,
621 Source
<NavigationController
>(
622 &shell()->web_contents()->GetController()));
624 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
625 client_redirect_http_url
));
627 // Same-site Client-Redirect Page should be loaded successfully.
628 EXPECT_EQ(observer
.navigation_url(), client_redirect_http_url
);
629 EXPECT_TRUE(observer
.navigation_succeeded());
631 // Redirecting to Cross-site Page should be blocked.
632 load_observer2
.Wait();
633 EXPECT_EQ(observer
.navigation_url(), https_url
);
634 EXPECT_FALSE(observer
.navigation_succeeded());
638 // Load same-site server-redirect page into Iframe,
639 // which redirects to same-site page.
640 GURL
server_redirect_http_url(test_server()->GetURL(
641 "server-redirect?files/title1.html"));
642 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
643 server_redirect_http_url
));
644 EXPECT_EQ(observer
.navigation_url(), http_url
);
645 EXPECT_TRUE(observer
.navigation_succeeded());
649 // Load same-site client-redirect page into Iframe,
650 // which redirects to same-site page.
651 GURL
client_redirect_http_url(test_server()->GetURL(
652 "client-redirect?" + http_url
.spec()));
653 RedirectNotificationObserver
load_observer2(
654 NOTIFICATION_LOAD_STOP
,
655 Source
<NavigationController
>(
656 &shell()->web_contents()->GetController()));
658 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
659 client_redirect_http_url
));
661 // Same-site Client-Redirect Page should be loaded successfully.
662 EXPECT_EQ(observer
.navigation_url(), client_redirect_http_url
);
663 EXPECT_TRUE(observer
.navigation_succeeded());
665 // Redirecting to Same-site Page should be loaded successfully.
666 load_observer2
.Wait();
667 EXPECT_EQ(observer
.navigation_url(), http_url
);
668 EXPECT_TRUE(observer
.navigation_succeeded());
672 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
673 // security checks are back in place.
674 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
675 // on Android (http://crbug.com/187570).
676 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
677 DISABLED_CrossSiteIframeRedirectTwice
) {
678 ASSERT_TRUE(test_server()->Start());
679 net::SpawnedTestServer
https_server(
680 net::SpawnedTestServer::TYPE_HTTPS
,
681 net::SpawnedTestServer::kLocalhost
,
682 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
683 ASSERT_TRUE(https_server
.Start());
685 GURL
main_url(test_server()->GetURL("files/site_per_process_main.html"));
686 GURL
http_url(test_server()->GetURL("files/title1.html"));
687 GURL
https_url(https_server
.GetURL("files/title1.html"));
689 NavigateToURL(shell(), main_url
);
691 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
693 // Load client-redirect page pointing to a cross-site client-redirect page,
694 // which eventually redirects back to same-site page.
695 GURL
client_redirect_https_url(https_server
.GetURL(
696 "client-redirect?" + http_url
.spec()));
697 GURL
client_redirect_http_url(test_server()->GetURL(
698 "client-redirect?" + client_redirect_https_url
.spec()));
700 // We should wait until second client redirect get cancelled.
701 RedirectNotificationObserver
load_observer2(
702 NOTIFICATION_LOAD_STOP
,
703 Source
<NavigationController
>(
704 &shell()->web_contents()->GetController()));
706 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
707 client_redirect_http_url
));
709 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
710 load_observer2
.Wait();
711 EXPECT_EQ(observer
.navigation_url(), client_redirect_https_url
);
712 EXPECT_FALSE(observer
.navigation_succeeded());
716 // Load server-redirect page pointing to a cross-site server-redirect page,
717 // which eventually redirect back to same-site page.
718 GURL
server_redirect_https_url(https_server
.GetURL(
719 "server-redirect?" + http_url
.spec()));
720 GURL
server_redirect_http_url(test_server()->GetURL(
721 "server-redirect?" + server_redirect_https_url
.spec()));
722 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
723 server_redirect_http_url
));
724 EXPECT_EQ(observer
.navigation_url(), http_url
);
725 EXPECT_TRUE(observer
.navigation_succeeded());
729 // Load server-redirect page pointing to a cross-site server-redirect page,
730 // which eventually redirects back to cross-site page.
731 GURL
server_redirect_https_url(https_server
.GetURL(
732 "server-redirect?" + https_url
.spec()));
733 GURL
server_redirect_http_url(test_server()->GetURL(
734 "server-redirect?" + server_redirect_https_url
.spec()));
735 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
736 server_redirect_http_url
));
738 // DidFailProvisionalLoad when navigating to https_url.
739 EXPECT_EQ(observer
.navigation_url(), https_url
);
740 EXPECT_FALSE(observer
.navigation_succeeded());
744 // Load server-redirect page pointing to a cross-site client-redirect page,
745 // which eventually redirects back to same-site page.
746 GURL
client_redirect_http_url(https_server
.GetURL(
747 "client-redirect?" + http_url
.spec()));
748 GURL
server_redirect_http_url(test_server()->GetURL(
749 "server-redirect?" + client_redirect_http_url
.spec()));
750 EXPECT_TRUE(NavigateIframeToURL(shell()->web_contents(), "test",
751 server_redirect_http_url
));
753 // DidFailProvisionalLoad when navigating to client_redirect_http_url.
754 EXPECT_EQ(observer
.navigation_url(), client_redirect_http_url
);
755 EXPECT_FALSE(observer
.navigation_succeeded());
759 // Ensure that when navigating a frame cross-process RenderFrameProxyHosts are
760 // created in the FrameTree skipping the subtree of the navigating frame.
762 // Disabled on Mac due to flakiness on ASAN. http://crbug.com/425248
763 // Disabled on Windows due to flakiness on Win 7 bot. http://crbug.com/444563
764 #if defined(OS_MACOSX) || defined(OS_WIN)
765 #define MAYBE_ProxyCreationSkipsSubtree DISABLED_ProxyCreationSkipsSubtree
767 #define MAYBE_ProxyCreationSkipsSubtree ProxyCreationSkipsSubtree
769 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
770 MAYBE_ProxyCreationSkipsSubtree
) {
771 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.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();
779 EXPECT_TRUE(root
->child_at(1) != NULL
);
780 EXPECT_EQ(2U, root
->child_at(1)->child_count());
783 // Load same-site page into iframe.
784 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
785 GURL
http_url(embedded_test_server()->GetURL("/title1.html"));
786 NavigateFrameToURL(root
->child_at(0), http_url
);
787 EXPECT_EQ(http_url
, observer
.navigation_url());
788 EXPECT_TRUE(observer
.navigation_succeeded());
789 RenderFrameProxyHost
* proxy_to_parent
=
790 root
->child_at(0)->render_manager()->GetRenderFrameProxyHost(
791 shell()->web_contents()->GetSiteInstance());
792 EXPECT_FALSE(proxy_to_parent
);
795 // Create the cross-site URL to navigate to.
796 GURL cross_site_url
=
797 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html");
799 // Load cross-site page into the second iframe without waiting for the
800 // navigation to complete. Once LoadURLWithParams returns, we would expect
801 // proxies to have been created in the frame tree, but children of the
802 // navigating frame to still be present. The reason is that we don't run the
803 // message loop, so no IPCs that alter the frame tree can be processed.
804 FrameTreeNode
* child
= root
->child_at(1);
805 SiteInstance
* site
= NULL
;
807 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
808 TestFrameNavigationObserver
navigation_observer(child
);
809 NavigationController::LoadURLParams
params(cross_site_url
);
810 params
.transition_type
= PageTransitionFromInt(ui::PAGE_TRANSITION_LINK
);
811 params
.frame_tree_node_id
= child
->frame_tree_node_id();
812 child
->navigator()->GetController()->LoadURLWithParams(params
);
813 EXPECT_TRUE(child
->render_manager()->pending_frame_host());
815 site
= child
->render_manager()->pending_frame_host()->GetSiteInstance();
816 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site
);
818 EXPECT_TRUE(root
->render_manager()->GetRenderFrameProxyHost(site
));
820 root
->child_at(0)->render_manager()->GetRenderFrameProxyHost(site
));
821 EXPECT_FALSE(child
->render_manager()->GetRenderFrameProxyHost(site
));
822 for (size_t i
= 0; i
< child
->child_count(); ++i
) {
824 child
->child_at(i
)->render_manager()->GetRenderFrameProxyHost(site
));
826 // Now that the verification is done, run the message loop and wait for the
827 // navigation to complete.
828 navigation_observer
.Wait();
829 EXPECT_FALSE(child
->render_manager()->pending_frame_host());
830 EXPECT_TRUE(observer
.navigation_succeeded());
831 EXPECT_EQ(cross_site_url
, observer
.navigation_url());
834 // Load another cross-site page into the same iframe.
835 cross_site_url
= embedded_test_server()->GetURL("bar.com", "/title2.html");
837 // Perform the same checks as the first cross-site navigation, since
838 // there have been issues in subsequent cross-site navigations. Also ensure
839 // that the SiteInstance has properly changed.
840 // TODO(nasko): Once we have proper cleanup of resources, add code to
841 // verify that the intermediate SiteInstance/RenderFrameHost have been
842 // properly cleaned up.
843 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
844 TestFrameNavigationObserver
navigation_observer(child
);
845 NavigationController::LoadURLParams
params(cross_site_url
);
846 params
.transition_type
= PageTransitionFromInt(ui::PAGE_TRANSITION_LINK
);
847 params
.frame_tree_node_id
= child
->frame_tree_node_id();
848 child
->navigator()->GetController()->LoadURLWithParams(params
);
849 EXPECT_TRUE(child
->render_manager()->pending_frame_host() != NULL
);
851 SiteInstance
* site2
=
852 child
->render_manager()->pending_frame_host()->GetSiteInstance();
853 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site2
);
854 EXPECT_NE(site
, site2
);
856 EXPECT_TRUE(root
->render_manager()->GetRenderFrameProxyHost(site2
));
858 root
->child_at(0)->render_manager()->GetRenderFrameProxyHost(site2
));
859 EXPECT_FALSE(child
->render_manager()->GetRenderFrameProxyHost(site2
));
860 for (size_t i
= 0; i
< child
->child_count(); ++i
) {
862 child
->child_at(i
)->render_manager()->GetRenderFrameProxyHost(site2
));
865 navigation_observer
.Wait();
866 EXPECT_TRUE(observer
.navigation_succeeded());
867 EXPECT_EQ(cross_site_url
, observer
.navigation_url());
868 EXPECT_EQ(0U, child
->child_count());
872 // Verify that origin replication works for an A-embed-B-embed-C hierarchy.
873 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, OriginReplication
) {
874 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
875 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
877 // It is safe to obtain the root frame tree node here, as it doesn't change.
878 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
882 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
884 // Navigate the first subframe to a cross-site page with two subframes.
885 // NavigateFrameToURL can't be used here because it doesn't guarantee that
886 // FrameTreeNodes will have been created for child frames when it returns.
887 RenderFrameHostCreatedObserver
frame_observer(shell()->web_contents(), 4);
889 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
890 NavigationController::LoadURLParams
params(foo_url
);
891 params
.transition_type
= ui::PAGE_TRANSITION_LINK
;
892 params
.frame_tree_node_id
= root
->child_at(0)->frame_tree_node_id();
893 root
->child_at(0)->navigator()->GetController()->LoadURLWithParams(params
);
894 frame_observer
.Wait();
896 // We can't use a SitePerProcessWebContentsObserver to verify the URL here,
897 // since the frame has children that may have clobbered it in the observer.
898 EXPECT_EQ(foo_url
, root
->child_at(0)->current_url());
900 // Ensure that a new process is created for the subframe.
901 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
902 root
->child_at(0)->current_frame_host()->GetSiteInstance());
904 // Load cross-site page into subframe's subframe.
905 ASSERT_EQ(2U, root
->child_at(0)->child_count());
906 GURL
bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
907 NavigateFrameToURL(root
->child_at(0)->child_at(0), bar_url
);
908 EXPECT_TRUE(observer
.navigation_succeeded());
909 EXPECT_EQ(bar_url
, observer
.navigation_url());
911 // Check that a new process is created and is different from the top one and
913 FrameTreeNode
* bottom_child
= root
->child_at(0)->child_at(0);
914 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
915 bottom_child
->current_frame_host()->GetSiteInstance());
916 EXPECT_NE(root
->child_at(0)->current_frame_host()->GetSiteInstance(),
917 bottom_child
->current_frame_host()->GetSiteInstance());
919 // Check that foo.com frame's location.ancestorOrigins contains the correct
920 // origin for the parent. The origin should have been replicated as part of
921 // the ViewMsg_New message that created the parent's RenderFrameProxy in
922 // foo.com's process.
923 int ancestor_origins_length
= 0;
924 EXPECT_TRUE(ExecuteScriptAndExtractInt(
925 root
->child_at(0)->current_frame_host(),
926 "window.domAutomationController.send(location.ancestorOrigins.length);",
927 &ancestor_origins_length
));
928 EXPECT_EQ(1, ancestor_origins_length
);
930 EXPECT_TRUE(ExecuteScriptAndExtractString(
931 root
->child_at(0)->current_frame_host(),
932 "window.domAutomationController.send(location.ancestorOrigins[0]);",
934 EXPECT_EQ(result
+ "/", main_url
.GetOrigin().spec());
936 // Check that bar.com frame's location.ancestorOrigins contains the correct
937 // origin for its two ancestors. The topmost parent origin should be
938 // replicated as part of ViewMsg_New, and the middle frame (foo.com's) origin
939 // should be replicated as part of FrameMsg_NewFrameProxy sent for foo.com's
940 // frame in bar.com's process.
941 EXPECT_TRUE(ExecuteScriptAndExtractInt(
942 bottom_child
->current_frame_host(),
943 "window.domAutomationController.send(location.ancestorOrigins.length);",
944 &ancestor_origins_length
));
945 EXPECT_EQ(2, ancestor_origins_length
);
946 EXPECT_TRUE(ExecuteScriptAndExtractString(
947 bottom_child
->current_frame_host(),
948 "window.domAutomationController.send(location.ancestorOrigins[0]);",
950 EXPECT_EQ(result
+ "/", foo_url
.GetOrigin().spec());
951 EXPECT_TRUE(ExecuteScriptAndExtractString(
952 bottom_child
->current_frame_host(),
953 "window.domAutomationController.send(location.ancestorOrigins[1]);",
955 EXPECT_EQ(result
+ "/", main_url
.GetOrigin().spec());
958 // TODO(lfg): Merge the test below with NavigateRemoteFrame test.
959 // TODO(lfg): Disabled because this triggers http://crbug.com/433012, and since
960 // the renderer process crashes, it causes the title watcher to never return.
961 // Alternatively, this could also be fixed if we could use NavigateIframeToURL
962 // and classified the navigation as MANUAL_SUBFRAME (http://crbug.com/441863) or
963 // if we waited for DidStopLoading (currently broken -- see comment in
964 // NavigateIframeToURL).
965 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
966 DISABLED_NavigateRemoteToDataURL
) {
967 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
968 NavigateToURL(shell(), main_url
);
970 // It is safe to obtain the root frame tree node here, as it doesn't change.
971 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
975 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
977 // Load cross-site page into iframe.
978 GURL url
= embedded_test_server()->GetURL("foo.com", "/title1.html");
979 NavigateFrameToURL(root
->child_at(0), url
);
980 EXPECT_TRUE(observer
.navigation_succeeded());
981 EXPECT_EQ(url
, observer
.navigation_url());
983 // Ensure that we have created a new process for the subframe.
984 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
985 root
->child_at(0)->current_frame_host()->GetSiteInstance());
987 // Navigate iframe to a data URL. The navigation happens from a script in the
988 // parent frame, so the data URL should be committed in the same SiteInstance
989 // as the parent frame.
990 GURL
data_url("data:text/html,dataurl");
991 std::string script
= base::StringPrintf(
992 "setTimeout(function() {"
993 "var iframe = document.getElementById('test');"
994 "iframe.onload = function() { document.title = 'LOADED'; };"
997 data_url
.spec().c_str());
998 base::string16
passed_string(base::UTF8ToUTF16("LOADED"));
999 TitleWatcher
title_watcher(shell()->web_contents(), passed_string
);
1000 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), script
));
1001 EXPECT_EQ(title_watcher
.WaitAndGetTitle(), passed_string
);
1002 EXPECT_TRUE(observer
.navigation_succeeded());
1003 EXPECT_EQ(data_url
, observer
.navigation_url());
1005 // Ensure that we have navigated using the top level process.
1006 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
1007 root
->child_at(0)->current_frame_host()->GetSiteInstance());
1010 // TODO(lfg): Merge the test below with NavigateRemoteFrame test.
1011 // Disabled due to the same reason as NavigateRemoteToDataURL.
1012 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
1013 DISABLED_NavigateRemoteToBlankURL
) {
1014 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1015 NavigateToURL(shell(), main_url
);
1017 // It is safe to obtain the root frame tree node here, as it doesn't change.
1018 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
1022 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
1024 // Load cross-site page into iframe.
1025 GURL url
= embedded_test_server()->GetURL("foo.com", "/title1.html");
1026 NavigateFrameToURL(root
->child_at(0), url
);
1027 EXPECT_TRUE(observer
.navigation_succeeded());
1028 EXPECT_EQ(url
, observer
.navigation_url());
1030 // Ensure that we have created a new process for the subframe.
1031 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
1032 root
->child_at(0)->current_frame_host()->GetSiteInstance());
1034 // Navigate iframe to about:blank. The navigation happens from a script in the
1035 // parent frame, so it should be committed in the same SiteInstance as the
1037 GURL
about_blank_url("about:blank");
1038 std::string script
= base::StringPrintf(
1039 "setTimeout(function() {"
1040 "var iframe = document.getElementById('test');"
1041 "iframe.onload = function() { document.title = 'LOADED'; };"
1042 "iframe.src=\"%s\";"
1044 about_blank_url
.spec().c_str());
1045 base::string16
passed_string(base::UTF8ToUTF16("LOADED"));
1046 TitleWatcher
title_watcher(shell()->web_contents(), passed_string
);
1047 EXPECT_TRUE(ExecuteScript(shell()->web_contents(), script
));
1048 EXPECT_EQ(title_watcher
.WaitAndGetTitle(), passed_string
);
1049 EXPECT_TRUE(observer
.navigation_succeeded());
1050 EXPECT_EQ(about_blank_url
, observer
.navigation_url());
1052 // Ensure that we have navigated using the top level process.
1053 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
1054 root
->child_at(0)->current_frame_host()->GetSiteInstance());
1057 // Ensure that navigating subframes in --site-per-process mode properly fires
1058 // the DidStopLoading event on WebContentsObserver.
1059 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, CrossSiteDidStopLoading
) {
1060 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
1061 NavigateToURL(shell(), main_url
);
1063 // It is safe to obtain the root frame tree node here, as it doesn't change.
1064 FrameTreeNode
* root
=
1065 static_cast<WebContentsImpl
*>(shell()->web_contents())->
1066 GetFrameTree()->root();
1068 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
1070 // Load same-site page into iframe.
1071 FrameTreeNode
* child
= root
->child_at(0);
1072 GURL
http_url(embedded_test_server()->GetURL("/title1.html"));
1073 NavigateFrameToURL(child
, http_url
);
1074 EXPECT_EQ(http_url
, observer
.navigation_url());
1075 EXPECT_TRUE(observer
.navigation_succeeded());
1077 // Load cross-site page into iframe.
1078 TestNavigationObserver
nav_observer(shell()->web_contents(), 1);
1079 GURL url
= embedded_test_server()->GetURL("foo.com", "/title2.html");
1080 NavigationController::LoadURLParams
params(url
);
1081 params
.transition_type
= ui::PAGE_TRANSITION_LINK
;
1082 params
.frame_tree_node_id
= child
->frame_tree_node_id();
1083 child
->navigator()->GetController()->LoadURLWithParams(params
);
1084 nav_observer
.Wait();
1086 // Verify that the navigation succeeded and the expected URL was loaded.
1087 EXPECT_TRUE(observer
.navigation_succeeded());
1088 EXPECT_EQ(url
, observer
.navigation_url());
1091 } // namespace content