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 "content/browser/frame_host/cross_process_frame_connector.h"
10 #include "content/browser/frame_host/frame_tree.h"
11 #include "content/browser/frame_host/navigator.h"
12 #include "content/browser/frame_host/render_frame_proxy_host.h"
13 #include "content/browser/frame_host/render_widget_host_view_child_frame.h"
14 #include "content/browser/renderer_host/render_view_host_impl.h"
15 #include "content/browser/web_contents/web_contents_impl.h"
16 #include "content/public/browser/notification_observer.h"
17 #include "content/public/browser/notification_service.h"
18 #include "content/public/browser/notification_types.h"
19 #include "content/public/browser/web_contents_observer.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_utils.h"
24 #include "content/shell/browser/shell.h"
25 #include "content/test/content_browser_test_utils_internal.h"
26 #include "content/test/test_frame_navigation_observer.h"
27 #include "net/dns/mock_host_resolver.h"
28 #include "net/test/embedded_test_server/embedded_test_server.h"
32 class SitePerProcessWebContentsObserver
: public WebContentsObserver
{
34 explicit SitePerProcessWebContentsObserver(WebContents
* web_contents
)
35 : WebContentsObserver(web_contents
),
36 navigation_succeeded_(false) {}
37 ~SitePerProcessWebContentsObserver() override
{}
39 void DidStartProvisionalLoadForFrame(RenderFrameHost
* render_frame_host
,
40 const GURL
& validated_url
,
42 bool is_iframe_srcdoc
) override
{
43 navigation_succeeded_
= false;
46 void DidFailProvisionalLoad(
47 RenderFrameHost
* render_frame_host
,
48 const GURL
& validated_url
,
50 const base::string16
& error_description
) override
{
51 navigation_url_
= validated_url
;
52 navigation_succeeded_
= false;
55 void DidCommitProvisionalLoadForFrame(
56 RenderFrameHost
* render_frame_host
,
58 ui::PageTransition transition_type
) override
{
59 navigation_url_
= url
;
60 navigation_succeeded_
= true;
63 const GURL
& navigation_url() const {
64 return navigation_url_
;
67 int navigation_succeeded() const { return navigation_succeeded_
; }
71 bool navigation_succeeded_
;
73 DISALLOW_COPY_AND_ASSIGN(SitePerProcessWebContentsObserver
);
76 class RedirectNotificationObserver
: public NotificationObserver
{
78 // Register to listen for notifications of the given type from either a
79 // specific source, or from all sources if |source| is
80 // NotificationService::AllSources().
81 RedirectNotificationObserver(int notification_type
,
82 const NotificationSource
& source
);
83 ~RedirectNotificationObserver() override
;
85 // Wait until the specified notification occurs. If the notification was
86 // emitted between the construction of this object and this call then it
87 // returns immediately.
90 // Returns NotificationService::AllSources() if we haven't observed a
92 const NotificationSource
& source() const {
96 const NotificationDetails
& details() const {
100 // NotificationObserver:
101 void Observe(int type
,
102 const NotificationSource
& source
,
103 const NotificationDetails
& details
) override
;
109 NotificationRegistrar registrar_
;
111 NotificationSource source_
;
112 NotificationDetails details_
;
113 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
115 DISALLOW_COPY_AND_ASSIGN(RedirectNotificationObserver
);
118 RedirectNotificationObserver::RedirectNotificationObserver(
119 int notification_type
,
120 const NotificationSource
& source
)
123 source_(NotificationService::AllSources()) {
124 registrar_
.Add(this, notification_type
, source
);
127 RedirectNotificationObserver::~RedirectNotificationObserver() {}
129 void RedirectNotificationObserver::Wait() {
130 if (seen_
&& seen_twice_
)
134 message_loop_runner_
= new MessageLoopRunner
;
135 message_loop_runner_
->Run();
139 void RedirectNotificationObserver::Observe(
141 const NotificationSource
& source
,
142 const NotificationDetails
& details
) {
150 message_loop_runner_
->Quit();
154 // This observer keeps track of the number of created RenderFrameHosts. Tests
155 // can use this to ensure that a certain number of child frames has been
156 // created after navigating.
157 class RenderFrameHostCreatedObserver
: public WebContentsObserver
{
159 RenderFrameHostCreatedObserver(WebContents
* web_contents
,
160 int expected_frame_count
)
161 : WebContentsObserver(web_contents
),
162 expected_frame_count_(expected_frame_count
),
164 message_loop_runner_(new MessageLoopRunner
) {}
166 ~RenderFrameHostCreatedObserver() override
;
168 // Runs a nested message loop and blocks until the expected number of
169 // RenderFrameHosts is created.
173 // WebContentsObserver
174 void RenderFrameCreated(RenderFrameHost
* render_frame_host
) override
;
176 // The number of RenderFrameHosts to wait for.
177 int expected_frame_count_
;
179 // The number of RenderFrameHosts that have been created.
182 // The MessageLoopRunner used to spin the message loop.
183 scoped_refptr
<MessageLoopRunner
> message_loop_runner_
;
185 DISALLOW_COPY_AND_ASSIGN(RenderFrameHostCreatedObserver
);
188 RenderFrameHostCreatedObserver::~RenderFrameHostCreatedObserver() {
191 void RenderFrameHostCreatedObserver::Wait() {
192 message_loop_runner_
->Run();
195 void RenderFrameHostCreatedObserver::RenderFrameCreated(
196 RenderFrameHost
* render_frame_host
) {
198 if (frames_created_
== expected_frame_count_
) {
199 message_loop_runner_
->Quit();
204 // SitePerProcessBrowserTest
207 SitePerProcessBrowserTest::SitePerProcessBrowserTest() {
210 void SitePerProcessBrowserTest::StartFrameAtDataURL() {
211 std::string data_url_script
=
212 "var iframes = document.getElementById('test');iframes.src="
213 "'data:text/html,dataurl';";
214 ASSERT_TRUE(ExecuteScript(shell()->web_contents(), data_url_script
));
217 bool SitePerProcessBrowserTest::NavigateIframeToURL(Shell
* window
,
219 std::string iframe_id
) {
220 // TODO(creis): This should wait for LOAD_STOP, but cross-site subframe
221 // navigations generate extra DidStartLoading and DidStopLoading messages.
222 // Until we replace swappedout:// with frame proxies, we need to listen for
223 // something else. For now, we trigger NEW_SUBFRAME navigations and listen
225 std::string script
= base::StringPrintf(
227 "var iframes = document.getElementById('%s');iframes.src='%s';"
229 iframe_id
.c_str(), url
.spec().c_str());
230 WindowedNotificationObserver
load_observer(
231 NOTIFICATION_NAV_ENTRY_COMMITTED
,
232 Source
<NavigationController
>(
233 &window
->web_contents()->GetController()));
234 bool result
= ExecuteScript(window
->web_contents(), script
);
235 load_observer
.Wait();
239 void SitePerProcessBrowserTest::SetUpCommandLine(CommandLine
* command_line
) {
240 command_line
->AppendSwitch(switches::kSitePerProcess
);
243 void SitePerProcessBrowserTest::SetUpOnMainThread() {
244 host_resolver()->AddRule("*", "127.0.0.1");
245 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
246 SetupCrossSiteRedirector(embedded_test_server());
249 // Ensure that navigating subframes in --site-per-process mode works and the
250 // correct documents are committed.
251 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, CrossSiteIframe
) {
252 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
253 NavigateToURL(shell(), main_url
);
255 // It is safe to obtain the root frame tree node here, as it doesn't change.
256 FrameTreeNode
* root
=
257 static_cast<WebContentsImpl
*>(shell()->web_contents())->
258 GetFrameTree()->root();
260 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
262 // Load same-site page into iframe.
263 FrameTreeNode
* child
= root
->child_at(0);
264 GURL
http_url(embedded_test_server()->GetURL("/title1.html"));
265 NavigateFrameToURL(child
, http_url
);
266 EXPECT_EQ(http_url
, observer
.navigation_url());
267 EXPECT_TRUE(observer
.navigation_succeeded());
269 // There should be only one RenderWidgetHost when there are no
270 // cross-process iframes.
271 std::set
<RenderWidgetHostView
*> views_set
=
272 static_cast<WebContentsImpl
*>(shell()->web_contents())
273 ->GetRenderWidgetHostViewsInTree();
274 EXPECT_EQ(1U, views_set
.size());
276 RenderFrameProxyHost
* proxy_to_parent
=
277 child
->render_manager()->GetRenderFrameProxyHost(
278 shell()->web_contents()->GetSiteInstance());
279 EXPECT_FALSE(proxy_to_parent
);
281 // Load cross-site page into iframe.
282 GURL url
= embedded_test_server()->GetURL("foo.com", "/title2.html");
283 NavigateFrameToURL(root
->child_at(0), url
);
284 // Verify that the navigation succeeded and the expected URL was loaded.
285 EXPECT_TRUE(observer
.navigation_succeeded());
286 EXPECT_EQ(url
, observer
.navigation_url());
288 // Ensure that we have created a new process for the subframe.
289 ASSERT_EQ(2U, root
->child_count());
290 SiteInstance
* site_instance
= child
->current_frame_host()->GetSiteInstance();
291 RenderViewHost
* rvh
= child
->current_frame_host()->render_view_host();
292 RenderProcessHost
* rph
= child
->current_frame_host()->GetProcess();
293 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh
);
294 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance
);
295 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), rph
);
297 // There should be now two RenderWidgetHosts, one for each process
298 // rendering a frame.
299 std::set
<RenderWidgetHostView
*> views_set
=
300 static_cast<WebContentsImpl
*>(shell()->web_contents())
301 ->GetRenderWidgetHostViewsInTree();
302 EXPECT_EQ(2U, views_set
.size());
304 proxy_to_parent
= child
->render_manager()->GetProxyToParent();
305 EXPECT_TRUE(proxy_to_parent
);
306 EXPECT_TRUE(proxy_to_parent
->cross_process_frame_connector());
309 proxy_to_parent
->cross_process_frame_connector()->get_view_for_testing());
311 // Load another cross-site page into the same iframe.
312 url
= embedded_test_server()->GetURL("bar.com", "/title3.html");
313 NavigateFrameToURL(root
->child_at(0), url
);
314 EXPECT_TRUE(observer
.navigation_succeeded());
315 EXPECT_EQ(url
, observer
.navigation_url());
317 // Check again that a new process is created and is different from the
318 // top level one and the previous one.
319 ASSERT_EQ(2U, root
->child_count());
320 child
= root
->child_at(0);
321 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(),
322 child
->current_frame_host()->render_view_host());
323 EXPECT_NE(rvh
, child
->current_frame_host()->render_view_host());
324 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
325 child
->current_frame_host()->GetSiteInstance());
326 EXPECT_NE(site_instance
,
327 child
->current_frame_host()->GetSiteInstance());
328 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(),
329 child
->current_frame_host()->GetProcess());
330 EXPECT_NE(rph
, child
->current_frame_host()->GetProcess());
332 std::set
<RenderWidgetHostView
*> views_set
=
333 static_cast<WebContentsImpl
*>(shell()->web_contents())
334 ->GetRenderWidgetHostViewsInTree();
335 EXPECT_EQ(2U, views_set
.size());
337 EXPECT_EQ(proxy_to_parent
, child
->render_manager()->GetProxyToParent());
338 EXPECT_TRUE(proxy_to_parent
->cross_process_frame_connector());
340 child
->current_frame_host()->render_view_host()->GetView(),
341 proxy_to_parent
->cross_process_frame_connector()->get_view_for_testing());
344 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, NavigateRemoteFrame
) {
345 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
346 NavigateToURL(shell(), main_url
);
348 // It is safe to obtain the root frame tree node here, as it doesn't change.
349 FrameTreeNode
* root
=
350 static_cast<WebContentsImpl
*>(shell()->web_contents())->
351 GetFrameTree()->root();
353 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
355 // Load same-site page into iframe.
356 FrameTreeNode
* child
= root
->child_at(0);
357 GURL
http_url(embedded_test_server()->GetURL("/title1.html"));
358 NavigateFrameToURL(child
, http_url
);
359 EXPECT_EQ(http_url
, observer
.navigation_url());
360 EXPECT_TRUE(observer
.navigation_succeeded());
362 // Load cross-site page into iframe.
363 GURL url
= embedded_test_server()->GetURL("foo.com", "/title2.html");
364 NavigateFrameToURL(root
->child_at(0), url
);
365 EXPECT_TRUE(observer
.navigation_succeeded());
366 EXPECT_EQ(url
, observer
.navigation_url());
368 // Ensure that we have created a new process for the subframe.
369 ASSERT_EQ(2U, root
->child_count());
370 SiteInstance
* site_instance
= child
->current_frame_host()->GetSiteInstance();
371 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance
);
373 // Emulate the main frame changing the src of the iframe such that it
374 // navigates cross-site.
375 url
= embedded_test_server()->GetURL("bar.com", "/title3.html");
376 NavigateIframeToURL(shell(), url
, "test");
377 EXPECT_TRUE(observer
.navigation_succeeded());
378 EXPECT_EQ(url
, observer
.navigation_url());
380 // Check again that a new process is created and is different from the
381 // top level one and the previous one.
382 ASSERT_EQ(2U, root
->child_count());
383 child
= root
->child_at(0);
384 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
385 child
->current_frame_host()->GetSiteInstance());
386 EXPECT_NE(site_instance
,
387 child
->current_frame_host()->GetSiteInstance());
389 // Navigate back to the parent's origin and ensure we return to the
391 NavigateFrameToURL(child
, http_url
);
392 EXPECT_EQ(http_url
, observer
.navigation_url());
393 EXPECT_TRUE(observer
.navigation_succeeded());
394 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
395 child
->current_frame_host()->GetSiteInstance());
398 // Crash a subframe and ensures its children are cleared from the FrameTree.
399 // See http://crbug.com/338508.
400 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, CrashSubframe
) {
401 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
402 NavigateToURL(shell(), main_url
);
404 StartFrameAtDataURL();
406 // These must stay in scope with replace_host.
407 GURL::Replacements replace_host
;
408 std::string
foo_com("foo.com");
410 // Load cross-site page into iframe.
411 EXPECT_TRUE(NavigateIframeToURL(
413 embedded_test_server()->GetURL("/cross-site/foo.com/title2.html"),
416 // Check the subframe process.
417 FrameTreeNode
* root
=
418 static_cast<WebContentsImpl
*>(shell()->web_contents())->
419 GetFrameTree()->root();
420 ASSERT_EQ(2U, root
->child_count());
421 FrameTreeNode
* child
= root
->child_at(0);
422 EXPECT_EQ(main_url
, root
->current_url());
423 EXPECT_EQ("foo.com", child
->current_url().host());
424 EXPECT_EQ("/title2.html", child
->current_url().path());
427 child
->current_frame_host()->render_view_host()->IsRenderViewLive());
428 EXPECT_TRUE(child
->current_frame_host()->IsRenderFrameLive());
430 // Crash the subframe process.
431 RenderProcessHost
* root_process
= root
->current_frame_host()->GetProcess();
432 RenderProcessHost
* child_process
= child
->current_frame_host()->GetProcess();
434 RenderProcessHostWatcher
crash_observer(
436 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
437 child_process
->Shutdown(0, false);
438 crash_observer
.Wait();
441 // Ensure that the child frame still exists but has been cleared.
442 EXPECT_EQ(2U, root
->child_count());
443 EXPECT_EQ(main_url
, root
->current_url());
444 EXPECT_EQ(GURL(), child
->current_url());
447 child
->current_frame_host()->render_view_host()->IsRenderViewLive());
448 EXPECT_FALSE(child
->current_frame_host()->IsRenderFrameLive());
449 EXPECT_FALSE(child
->current_frame_host()->render_frame_created_
);
451 // Now crash the top-level page to clear the child frame.
453 RenderProcessHostWatcher
crash_observer(
455 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
456 root_process
->Shutdown(0, false);
457 crash_observer
.Wait();
459 EXPECT_EQ(0U, root
->child_count());
460 EXPECT_EQ(GURL(), root
->current_url());
463 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
464 // security checks are back in place.
465 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
466 // on Android (http://crbug.com/187570).
467 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
468 DISABLED_CrossSiteIframeRedirectOnce
) {
469 ASSERT_TRUE(test_server()->Start());
470 net::SpawnedTestServer
https_server(
471 net::SpawnedTestServer::TYPE_HTTPS
,
472 net::SpawnedTestServer::kLocalhost
,
473 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
474 ASSERT_TRUE(https_server
.Start());
476 GURL
main_url(test_server()->GetURL("files/site_per_process_main.html"));
477 GURL
http_url(test_server()->GetURL("files/title1.html"));
478 GURL
https_url(https_server
.GetURL("files/title1.html"));
480 NavigateToURL(shell(), main_url
);
482 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
484 // Load cross-site client-redirect page into Iframe.
485 // Should be blocked.
486 GURL
client_redirect_https_url(https_server
.GetURL(
487 "client-redirect?files/title1.html"));
488 EXPECT_TRUE(NavigateIframeToURL(shell(),
489 client_redirect_https_url
, "test"));
490 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
491 EXPECT_EQ(observer
.navigation_url(), client_redirect_https_url
);
492 EXPECT_FALSE(observer
.navigation_succeeded());
496 // Load cross-site server-redirect page into Iframe,
497 // which redirects to same-site page.
498 GURL
server_redirect_http_url(https_server
.GetURL(
499 "server-redirect?" + http_url
.spec()));
500 EXPECT_TRUE(NavigateIframeToURL(shell(),
501 server_redirect_http_url
, "test"));
502 EXPECT_EQ(observer
.navigation_url(), http_url
);
503 EXPECT_TRUE(observer
.navigation_succeeded());
507 // Load cross-site server-redirect page into Iframe,
508 // which redirects to cross-site page.
509 GURL
server_redirect_http_url(https_server
.GetURL(
510 "server-redirect?files/title1.html"));
511 EXPECT_TRUE(NavigateIframeToURL(shell(),
512 server_redirect_http_url
, "test"));
513 // DidFailProvisionalLoad when navigating to https_url.
514 EXPECT_EQ(observer
.navigation_url(), https_url
);
515 EXPECT_FALSE(observer
.navigation_succeeded());
519 // Load same-site server-redirect page into Iframe,
520 // which redirects to cross-site page.
521 GURL
server_redirect_http_url(test_server()->GetURL(
522 "server-redirect?" + https_url
.spec()));
523 EXPECT_TRUE(NavigateIframeToURL(shell(),
524 server_redirect_http_url
, "test"));
526 EXPECT_EQ(observer
.navigation_url(), https_url
);
527 EXPECT_FALSE(observer
.navigation_succeeded());
531 // Load same-site client-redirect page into Iframe,
532 // which redirects to cross-site page.
533 GURL
client_redirect_http_url(test_server()->GetURL(
534 "client-redirect?" + https_url
.spec()));
536 RedirectNotificationObserver
load_observer2(
537 NOTIFICATION_LOAD_STOP
,
538 Source
<NavigationController
>(
539 &shell()->web_contents()->GetController()));
541 EXPECT_TRUE(NavigateIframeToURL(shell(),
542 client_redirect_http_url
, "test"));
544 // Same-site Client-Redirect Page should be loaded successfully.
545 EXPECT_EQ(observer
.navigation_url(), client_redirect_http_url
);
546 EXPECT_TRUE(observer
.navigation_succeeded());
548 // Redirecting to Cross-site Page should be blocked.
549 load_observer2
.Wait();
550 EXPECT_EQ(observer
.navigation_url(), https_url
);
551 EXPECT_FALSE(observer
.navigation_succeeded());
555 // Load same-site server-redirect page into Iframe,
556 // which redirects to same-site page.
557 GURL
server_redirect_http_url(test_server()->GetURL(
558 "server-redirect?files/title1.html"));
559 EXPECT_TRUE(NavigateIframeToURL(shell(),
560 server_redirect_http_url
, "test"));
561 EXPECT_EQ(observer
.navigation_url(), http_url
);
562 EXPECT_TRUE(observer
.navigation_succeeded());
566 // Load same-site client-redirect page into Iframe,
567 // which redirects to same-site page.
568 GURL
client_redirect_http_url(test_server()->GetURL(
569 "client-redirect?" + http_url
.spec()));
570 RedirectNotificationObserver
load_observer2(
571 NOTIFICATION_LOAD_STOP
,
572 Source
<NavigationController
>(
573 &shell()->web_contents()->GetController()));
575 EXPECT_TRUE(NavigateIframeToURL(shell(),
576 client_redirect_http_url
, "test"));
578 // Same-site Client-Redirect Page should be loaded successfully.
579 EXPECT_EQ(observer
.navigation_url(), client_redirect_http_url
);
580 EXPECT_TRUE(observer
.navigation_succeeded());
582 // Redirecting to Same-site Page should be loaded successfully.
583 load_observer2
.Wait();
584 EXPECT_EQ(observer
.navigation_url(), http_url
);
585 EXPECT_TRUE(observer
.navigation_succeeded());
589 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
590 // security checks are back in place.
591 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
592 // on Android (http://crbug.com/187570).
593 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
594 DISABLED_CrossSiteIframeRedirectTwice
) {
595 ASSERT_TRUE(test_server()->Start());
596 net::SpawnedTestServer
https_server(
597 net::SpawnedTestServer::TYPE_HTTPS
,
598 net::SpawnedTestServer::kLocalhost
,
599 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
600 ASSERT_TRUE(https_server
.Start());
602 GURL
main_url(test_server()->GetURL("files/site_per_process_main.html"));
603 GURL
http_url(test_server()->GetURL("files/title1.html"));
604 GURL
https_url(https_server
.GetURL("files/title1.html"));
606 NavigateToURL(shell(), main_url
);
608 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
610 // Load client-redirect page pointing to a cross-site client-redirect page,
611 // which eventually redirects back to same-site page.
612 GURL
client_redirect_https_url(https_server
.GetURL(
613 "client-redirect?" + http_url
.spec()));
614 GURL
client_redirect_http_url(test_server()->GetURL(
615 "client-redirect?" + client_redirect_https_url
.spec()));
617 // We should wait until second client redirect get cancelled.
618 RedirectNotificationObserver
load_observer2(
619 NOTIFICATION_LOAD_STOP
,
620 Source
<NavigationController
>(
621 &shell()->web_contents()->GetController()));
623 EXPECT_TRUE(NavigateIframeToURL(shell(), client_redirect_http_url
, "test"));
625 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
626 load_observer2
.Wait();
627 EXPECT_EQ(observer
.navigation_url(), client_redirect_https_url
);
628 EXPECT_FALSE(observer
.navigation_succeeded());
632 // Load server-redirect page pointing to a cross-site server-redirect page,
633 // which eventually redirect back to same-site page.
634 GURL
server_redirect_https_url(https_server
.GetURL(
635 "server-redirect?" + http_url
.spec()));
636 GURL
server_redirect_http_url(test_server()->GetURL(
637 "server-redirect?" + server_redirect_https_url
.spec()));
638 EXPECT_TRUE(NavigateIframeToURL(shell(),
639 server_redirect_http_url
, "test"));
640 EXPECT_EQ(observer
.navigation_url(), http_url
);
641 EXPECT_TRUE(observer
.navigation_succeeded());
645 // Load server-redirect page pointing to a cross-site server-redirect page,
646 // which eventually redirects back to cross-site page.
647 GURL
server_redirect_https_url(https_server
.GetURL(
648 "server-redirect?" + https_url
.spec()));
649 GURL
server_redirect_http_url(test_server()->GetURL(
650 "server-redirect?" + server_redirect_https_url
.spec()));
651 EXPECT_TRUE(NavigateIframeToURL(shell(), server_redirect_http_url
, "test"));
653 // DidFailProvisionalLoad when navigating to https_url.
654 EXPECT_EQ(observer
.navigation_url(), https_url
);
655 EXPECT_FALSE(observer
.navigation_succeeded());
659 // Load server-redirect page pointing to a cross-site client-redirect page,
660 // which eventually redirects back to same-site page.
661 GURL
client_redirect_http_url(https_server
.GetURL(
662 "client-redirect?" + http_url
.spec()));
663 GURL
server_redirect_http_url(test_server()->GetURL(
664 "server-redirect?" + client_redirect_http_url
.spec()));
665 EXPECT_TRUE(NavigateIframeToURL(shell(), server_redirect_http_url
, "test"));
667 // DidFailProvisionalLoad when navigating to client_redirect_http_url.
668 EXPECT_EQ(observer
.navigation_url(), client_redirect_http_url
);
669 EXPECT_FALSE(observer
.navigation_succeeded());
673 // Ensure that when navigating a frame cross-process RenderFrameProxyHosts are
674 // created in the FrameTree skipping the subtree of the navigating frame.
676 // Disabled on Mac due to flakiness on ASAN. http://crbug.com/425248
677 #if defined(OS_MACOSX)
678 #define MAYBE_ProxyCreationSkipsSubtree DISABLED_ProxyCreationSkipsSubtree
680 #define MAYBE_ProxyCreationSkipsSubtree ProxyCreationSkipsSubtree
682 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
683 MAYBE_ProxyCreationSkipsSubtree
) {
684 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
685 NavigateToURL(shell(), main_url
);
687 // It is safe to obtain the root frame tree node here, as it doesn't change.
688 FrameTreeNode
* root
=
689 static_cast<WebContentsImpl
*>(shell()->web_contents())->
690 GetFrameTree()->root();
692 EXPECT_TRUE(root
->child_at(1) != NULL
);
693 EXPECT_EQ(2U, root
->child_at(1)->child_count());
696 // Load same-site page into iframe.
697 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
698 GURL
http_url(embedded_test_server()->GetURL("/title1.html"));
699 NavigateFrameToURL(root
->child_at(0), http_url
);
700 EXPECT_EQ(http_url
, observer
.navigation_url());
701 EXPECT_TRUE(observer
.navigation_succeeded());
702 RenderFrameProxyHost
* proxy_to_parent
=
703 root
->child_at(0)->render_manager()->GetRenderFrameProxyHost(
704 shell()->web_contents()->GetSiteInstance());
705 EXPECT_FALSE(proxy_to_parent
);
708 // Create the cross-site URL to navigate to.
709 GURL cross_site_url
=
710 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html");
712 // Load cross-site page into the second iframe without waiting for the
713 // navigation to complete. Once LoadURLWithParams returns, we would expect
714 // proxies to have been created in the frame tree, but children of the
715 // navigating frame to still be present. The reason is that we don't run the
716 // message loop, so no IPCs that alter the frame tree can be processed.
717 FrameTreeNode
* child
= root
->child_at(1);
718 SiteInstance
* site
= NULL
;
720 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
721 TestFrameNavigationObserver
navigation_observer(child
);
722 NavigationController::LoadURLParams
params(cross_site_url
);
723 params
.transition_type
= PageTransitionFromInt(ui::PAGE_TRANSITION_LINK
);
724 params
.frame_tree_node_id
= child
->frame_tree_node_id();
725 child
->navigator()->GetController()->LoadURLWithParams(params
);
726 EXPECT_TRUE(child
->render_manager()->pending_frame_host());
728 site
= child
->render_manager()->pending_frame_host()->GetSiteInstance();
729 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site
);
731 EXPECT_TRUE(root
->render_manager()->GetRenderFrameProxyHost(site
));
733 root
->child_at(0)->render_manager()->GetRenderFrameProxyHost(site
));
734 EXPECT_FALSE(child
->render_manager()->GetRenderFrameProxyHost(site
));
735 for (size_t i
= 0; i
< child
->child_count(); ++i
) {
737 child
->child_at(i
)->render_manager()->GetRenderFrameProxyHost(site
));
739 // Now that the verification is done, run the message loop and wait for the
740 // navigation to complete.
741 navigation_observer
.Wait();
742 EXPECT_FALSE(child
->render_manager()->pending_frame_host());
743 EXPECT_TRUE(observer
.navigation_succeeded());
744 EXPECT_EQ(cross_site_url
, observer
.navigation_url());
747 // Load another cross-site page into the same iframe.
748 cross_site_url
= embedded_test_server()->GetURL("bar.com", "/title2.html");
750 // Perform the same checks as the first cross-site navigation, since
751 // there have been issues in subsequent cross-site navigations. Also ensure
752 // that the SiteInstance has properly changed.
753 // TODO(nasko): Once we have proper cleanup of resources, add code to
754 // verify that the intermediate SiteInstance/RenderFrameHost have been
755 // properly cleaned up.
756 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
757 TestFrameNavigationObserver
navigation_observer(child
);
758 NavigationController::LoadURLParams
params(cross_site_url
);
759 params
.transition_type
= PageTransitionFromInt(ui::PAGE_TRANSITION_LINK
);
760 params
.frame_tree_node_id
= child
->frame_tree_node_id();
761 child
->navigator()->GetController()->LoadURLWithParams(params
);
762 EXPECT_TRUE(child
->render_manager()->pending_frame_host() != NULL
);
764 SiteInstance
* site2
=
765 child
->render_manager()->pending_frame_host()->GetSiteInstance();
766 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site2
);
767 EXPECT_NE(site
, site2
);
769 EXPECT_TRUE(root
->render_manager()->GetRenderFrameProxyHost(site2
));
771 root
->child_at(0)->render_manager()->GetRenderFrameProxyHost(site2
));
772 EXPECT_FALSE(child
->render_manager()->GetRenderFrameProxyHost(site2
));
773 for (size_t i
= 0; i
< child
->child_count(); ++i
) {
775 child
->child_at(i
)->render_manager()->GetRenderFrameProxyHost(site2
));
778 navigation_observer
.Wait();
779 EXPECT_TRUE(observer
.navigation_succeeded());
780 EXPECT_EQ(cross_site_url
, observer
.navigation_url());
781 EXPECT_EQ(0U, child
->child_count());
785 // Verify that origin replication works for an A-embed-B-embed-C hierarchy.
786 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, OriginReplication
) {
787 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
788 EXPECT_TRUE(NavigateToURL(shell(), main_url
));
790 // It is safe to obtain the root frame tree node here, as it doesn't change.
791 FrameTreeNode
* root
= static_cast<WebContentsImpl
*>(shell()->web_contents())
795 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
797 // Navigate the first subframe to a cross-site page with two subframes.
798 // NavigateFrameToURL can't be used here because it doesn't guarantee that
799 // FrameTreeNodes will have been created for child frames when it returns.
800 RenderFrameHostCreatedObserver
frame_observer(shell()->web_contents(), 3);
802 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html"));
803 NavigationController::LoadURLParams
params(foo_url
);
804 params
.transition_type
= ui::PAGE_TRANSITION_LINK
;
805 params
.frame_tree_node_id
= root
->child_at(0)->frame_tree_node_id();
806 root
->child_at(0)->navigator()->GetController()->LoadURLWithParams(params
);
807 frame_observer
.Wait();
809 // We can't use a SitePerProcessWebContentsObserver to verify the URL here,
810 // since the frame has children that may have clobbered it in the observer.
811 EXPECT_EQ(foo_url
, root
->child_at(0)->current_url());
813 // Ensure that a new process is created for the subframe.
814 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
815 root
->child_at(0)->current_frame_host()->GetSiteInstance());
817 // Load cross-site page into subframe's subframe.
818 ASSERT_EQ(2U, root
->child_at(0)->child_count());
819 GURL
bar_url(embedded_test_server()->GetURL("bar.com", "/title1.html"));
820 NavigateFrameToURL(root
->child_at(0)->child_at(0), bar_url
);
821 EXPECT_TRUE(observer
.navigation_succeeded());
822 EXPECT_EQ(bar_url
, observer
.navigation_url());
824 // Check that a new process is created and is different from the top one and
826 FrameTreeNode
* bottom_child
= root
->child_at(0)->child_at(0);
827 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
828 bottom_child
->current_frame_host()->GetSiteInstance());
829 EXPECT_NE(root
->child_at(0)->current_frame_host()->GetSiteInstance(),
830 bottom_child
->current_frame_host()->GetSiteInstance());
832 // Check that foo.com frame's location.ancestorOrigins contains the correct
833 // origin for the parent. The origin should have been replicated as part of
834 // the ViewMsg_New message that created the parent's RenderFrameProxy in
835 // foo.com's process.
836 int ancestor_origins_length
= 0;
837 EXPECT_TRUE(ExecuteScriptAndExtractInt(
838 root
->child_at(0)->current_frame_host(),
839 "window.domAutomationController.send(location.ancestorOrigins.length);",
840 &ancestor_origins_length
));
841 EXPECT_EQ(1, ancestor_origins_length
);
843 EXPECT_TRUE(ExecuteScriptAndExtractString(
844 root
->child_at(0)->current_frame_host(),
845 "window.domAutomationController.send(location.ancestorOrigins[0]);",
847 EXPECT_EQ(result
+ "/", main_url
.GetOrigin().spec());
849 // Check that bar.com frame's location.ancestorOrigins contains the correct
850 // origin for its two ancestors. The topmost parent origin should be
851 // replicated as part of ViewMsg_New, and the middle frame (foo.com's) origin
852 // should be replicated as part of FrameMsg_NewFrameProxy sent for foo.com's
853 // frame in bar.com's process.
854 EXPECT_TRUE(ExecuteScriptAndExtractInt(
855 bottom_child
->current_frame_host(),
856 "window.domAutomationController.send(location.ancestorOrigins.length);",
857 &ancestor_origins_length
));
858 EXPECT_EQ(2, ancestor_origins_length
);
859 EXPECT_TRUE(ExecuteScriptAndExtractString(
860 bottom_child
->current_frame_host(),
861 "window.domAutomationController.send(location.ancestorOrigins[0]);",
863 EXPECT_EQ(result
+ "/", foo_url
.GetOrigin().spec());
864 EXPECT_TRUE(ExecuteScriptAndExtractString(
865 bottom_child
->current_frame_host(),
866 "window.domAutomationController.send(location.ancestorOrigins[1]);",
868 EXPECT_EQ(result
+ "/", main_url
.GetOrigin().spec());
871 } // namespace content