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();
155 // SitePerProcessBrowserTest
158 SitePerProcessBrowserTest::SitePerProcessBrowserTest() {
161 void SitePerProcessBrowserTest::StartFrameAtDataURL() {
162 std::string data_url_script
=
163 "var iframes = document.getElementById('test');iframes.src="
164 "'data:text/html,dataurl';";
165 ASSERT_TRUE(ExecuteScript(shell()->web_contents(), data_url_script
));
168 bool SitePerProcessBrowserTest::NavigateIframeToURL(Shell
* window
,
170 std::string iframe_id
) {
171 // TODO(creis): This should wait for LOAD_STOP, but cross-site subframe
172 // navigations generate extra DidStartLoading and DidStopLoading messages.
173 // Until we replace swappedout:// with frame proxies, we need to listen for
174 // something else. For now, we trigger NEW_SUBFRAME navigations and listen
176 std::string script
= base::StringPrintf(
178 "var iframes = document.getElementById('%s');iframes.src='%s';"
180 iframe_id
.c_str(), url
.spec().c_str());
181 WindowedNotificationObserver
load_observer(
182 NOTIFICATION_NAV_ENTRY_COMMITTED
,
183 Source
<NavigationController
>(
184 &window
->web_contents()->GetController()));
185 bool result
= ExecuteScript(window
->web_contents(), script
);
186 load_observer
.Wait();
190 void SitePerProcessBrowserTest::SetUpCommandLine(CommandLine
* command_line
) {
191 command_line
->AppendSwitch(switches::kSitePerProcess
);
194 void SitePerProcessBrowserTest::SetUpOnMainThread() {
195 host_resolver()->AddRule("*", "127.0.0.1");
196 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
197 SetupCrossSiteRedirector(embedded_test_server());
200 // Ensure that navigating subframes in --site-per-process mode works and the
201 // correct documents are committed.
202 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, CrossSiteIframe
) {
203 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
204 NavigateToURL(shell(), main_url
);
206 // It is safe to obtain the root frame tree node here, as it doesn't change.
207 FrameTreeNode
* root
=
208 static_cast<WebContentsImpl
*>(shell()->web_contents())->
209 GetFrameTree()->root();
211 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
213 // Load same-site page into iframe.
214 FrameTreeNode
* child
= root
->child_at(0);
215 GURL
http_url(embedded_test_server()->GetURL("/title1.html"));
216 NavigateFrameToURL(child
, http_url
);
217 EXPECT_EQ(http_url
, observer
.navigation_url());
218 EXPECT_TRUE(observer
.navigation_succeeded());
220 // There should be only one RenderWidgetHost when there are no
221 // cross-process iframes.
222 std::set
<RenderWidgetHostView
*> views_set
=
223 static_cast<WebContentsImpl
*>(shell()->web_contents())
224 ->GetRenderWidgetHostViewsInTree();
225 EXPECT_EQ(1U, views_set
.size());
227 RenderFrameProxyHost
* proxy_to_parent
=
228 child
->render_manager()->GetRenderFrameProxyHost(
229 shell()->web_contents()->GetSiteInstance());
230 EXPECT_FALSE(proxy_to_parent
);
232 // Load cross-site page into iframe.
233 GURL url
= embedded_test_server()->GetURL("foo.com", "/title2.html");
234 NavigateFrameToURL(root
->child_at(0), url
);
235 // Verify that the navigation succeeded and the expected URL was loaded.
236 EXPECT_TRUE(observer
.navigation_succeeded());
237 EXPECT_EQ(url
, observer
.navigation_url());
239 // Ensure that we have created a new process for the subframe.
240 ASSERT_EQ(2U, root
->child_count());
241 SiteInstance
* site_instance
= child
->current_frame_host()->GetSiteInstance();
242 RenderViewHost
* rvh
= child
->current_frame_host()->render_view_host();
243 RenderProcessHost
* rph
= child
->current_frame_host()->GetProcess();
244 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh
);
245 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance
);
246 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), rph
);
248 // There should be now two RenderWidgetHosts, one for each process
249 // rendering a frame.
250 std::set
<RenderWidgetHostView
*> views_set
=
251 static_cast<WebContentsImpl
*>(shell()->web_contents())
252 ->GetRenderWidgetHostViewsInTree();
253 EXPECT_EQ(2U, views_set
.size());
255 proxy_to_parent
= child
->render_manager()->GetProxyToParent();
256 EXPECT_TRUE(proxy_to_parent
);
257 EXPECT_TRUE(proxy_to_parent
->cross_process_frame_connector());
260 proxy_to_parent
->cross_process_frame_connector()->get_view_for_testing());
262 // Load another cross-site page into the same iframe.
263 url
= embedded_test_server()->GetURL("bar.com", "/title3.html");
264 NavigateFrameToURL(root
->child_at(0), url
);
265 EXPECT_TRUE(observer
.navigation_succeeded());
266 EXPECT_EQ(url
, observer
.navigation_url());
268 // Check again that a new process is created and is different from the
269 // top level one and the previous one.
270 ASSERT_EQ(2U, root
->child_count());
271 child
= root
->child_at(0);
272 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(),
273 child
->current_frame_host()->render_view_host());
274 EXPECT_NE(rvh
, child
->current_frame_host()->render_view_host());
275 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
276 child
->current_frame_host()->GetSiteInstance());
277 EXPECT_NE(site_instance
,
278 child
->current_frame_host()->GetSiteInstance());
279 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(),
280 child
->current_frame_host()->GetProcess());
281 EXPECT_NE(rph
, child
->current_frame_host()->GetProcess());
283 std::set
<RenderWidgetHostView
*> views_set
=
284 static_cast<WebContentsImpl
*>(shell()->web_contents())
285 ->GetRenderWidgetHostViewsInTree();
286 EXPECT_EQ(2U, views_set
.size());
288 EXPECT_EQ(proxy_to_parent
, child
->render_manager()->GetProxyToParent());
289 EXPECT_TRUE(proxy_to_parent
->cross_process_frame_connector());
291 child
->current_frame_host()->render_view_host()->GetView(),
292 proxy_to_parent
->cross_process_frame_connector()->get_view_for_testing());
295 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, NavigateRemoteFrame
) {
296 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
297 NavigateToURL(shell(), main_url
);
299 // It is safe to obtain the root frame tree node here, as it doesn't change.
300 FrameTreeNode
* root
=
301 static_cast<WebContentsImpl
*>(shell()->web_contents())->
302 GetFrameTree()->root();
304 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
306 // Load same-site page into iframe.
307 FrameTreeNode
* child
= root
->child_at(0);
308 GURL
http_url(embedded_test_server()->GetURL("/title1.html"));
309 NavigateFrameToURL(child
, http_url
);
310 EXPECT_EQ(http_url
, observer
.navigation_url());
311 EXPECT_TRUE(observer
.navigation_succeeded());
313 // Load cross-site page into iframe.
314 GURL url
= embedded_test_server()->GetURL("foo.com", "/title2.html");
315 NavigateFrameToURL(root
->child_at(0), url
);
316 EXPECT_TRUE(observer
.navigation_succeeded());
317 EXPECT_EQ(url
, observer
.navigation_url());
319 // Ensure that we have created a new process for the subframe.
320 ASSERT_EQ(2U, root
->child_count());
321 SiteInstance
* site_instance
= child
->current_frame_host()->GetSiteInstance();
322 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance
);
324 // Emulate the main frame changing the src of the iframe such that it
325 // navigates cross-site.
326 url
= embedded_test_server()->GetURL("bar.com", "/title3.html");
327 NavigateIframeToURL(shell(), url
, "test");
328 EXPECT_TRUE(observer
.navigation_succeeded());
329 EXPECT_EQ(url
, observer
.navigation_url());
331 // Check again that a new process is created and is different from the
332 // top level one and the previous one.
333 ASSERT_EQ(2U, root
->child_count());
334 child
= root
->child_at(0);
335 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
336 child
->current_frame_host()->GetSiteInstance());
337 EXPECT_NE(site_instance
,
338 child
->current_frame_host()->GetSiteInstance());
340 // Navigate back to the parent's origin and ensure we return to the
342 NavigateFrameToURL(child
, http_url
);
343 EXPECT_EQ(http_url
, observer
.navigation_url());
344 EXPECT_TRUE(observer
.navigation_succeeded());
345 EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
346 child
->current_frame_host()->GetSiteInstance());
349 // Crash a subframe and ensures its children are cleared from the FrameTree.
350 // See http://crbug.com/338508.
351 // TODO(creis): Disabled for flakiness; see http://crbug.com/405582.
352 // TODO(creis): Enable this on Android when we can kill the process there.
353 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
, DISABLED_CrashSubframe
) {
354 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
355 NavigateToURL(shell(), main_url
);
357 StartFrameAtDataURL();
359 // These must stay in scope with replace_host.
360 GURL::Replacements replace_host
;
361 std::string
foo_com("foo.com");
363 // Load cross-site page into iframe.
364 EXPECT_TRUE(NavigateIframeToURL(
366 embedded_test_server()->GetURL("/cross-site/foo.com/title2.html"),
369 // Check the subframe process.
370 FrameTreeNode
* root
=
371 static_cast<WebContentsImpl
*>(shell()->web_contents())->
372 GetFrameTree()->root();
373 ASSERT_EQ(1U, root
->child_count());
374 FrameTreeNode
* child
= root
->child_at(0);
375 EXPECT_EQ(main_url
, root
->current_url());
376 EXPECT_EQ("foo.com", child
->current_url().host());
377 EXPECT_EQ("/title2.html", child
->current_url().path());
380 child
->current_frame_host()->render_view_host()->IsRenderViewLive());
381 EXPECT_TRUE(child
->current_frame_host()->IsRenderFrameLive());
383 // Crash the subframe process.
384 RenderProcessHost
* root_process
= root
->current_frame_host()->GetProcess();
385 RenderProcessHost
* child_process
= child
->current_frame_host()->GetProcess();
387 RenderProcessHostWatcher
crash_observer(
389 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
390 base::KillProcess(child_process
->GetHandle(), 0, false);
391 crash_observer
.Wait();
394 // Ensure that the child frame still exists but has been cleared.
395 EXPECT_EQ(1U, root
->child_count());
396 EXPECT_EQ(main_url
, root
->current_url());
397 EXPECT_EQ(GURL(), child
->current_url());
400 child
->current_frame_host()->render_view_host()->IsRenderViewLive());
401 EXPECT_FALSE(child
->current_frame_host()->IsRenderFrameLive());
402 EXPECT_FALSE(child
->current_frame_host()->render_frame_created_
);
404 // Now crash the top-level page to clear the child frame.
406 RenderProcessHostWatcher
crash_observer(
408 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT
);
409 base::KillProcess(root_process
->GetHandle(), 0, false);
410 crash_observer
.Wait();
412 EXPECT_EQ(0U, root
->child_count());
413 EXPECT_EQ(GURL(), root
->current_url());
416 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
417 // security checks are back in place.
418 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
419 // on Android (http://crbug.com/187570).
420 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
421 DISABLED_CrossSiteIframeRedirectOnce
) {
422 ASSERT_TRUE(test_server()->Start());
423 net::SpawnedTestServer
https_server(
424 net::SpawnedTestServer::TYPE_HTTPS
,
425 net::SpawnedTestServer::kLocalhost
,
426 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
427 ASSERT_TRUE(https_server
.Start());
429 GURL
main_url(test_server()->GetURL("files/site_per_process_main.html"));
430 GURL
http_url(test_server()->GetURL("files/title1.html"));
431 GURL
https_url(https_server
.GetURL("files/title1.html"));
433 NavigateToURL(shell(), main_url
);
435 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
437 // Load cross-site client-redirect page into Iframe.
438 // Should be blocked.
439 GURL
client_redirect_https_url(https_server
.GetURL(
440 "client-redirect?files/title1.html"));
441 EXPECT_TRUE(NavigateIframeToURL(shell(),
442 client_redirect_https_url
, "test"));
443 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
444 EXPECT_EQ(observer
.navigation_url(), client_redirect_https_url
);
445 EXPECT_FALSE(observer
.navigation_succeeded());
449 // Load cross-site server-redirect page into Iframe,
450 // which redirects to same-site page.
451 GURL
server_redirect_http_url(https_server
.GetURL(
452 "server-redirect?" + http_url
.spec()));
453 EXPECT_TRUE(NavigateIframeToURL(shell(),
454 server_redirect_http_url
, "test"));
455 EXPECT_EQ(observer
.navigation_url(), http_url
);
456 EXPECT_TRUE(observer
.navigation_succeeded());
460 // Load cross-site server-redirect page into Iframe,
461 // which redirects to cross-site page.
462 GURL
server_redirect_http_url(https_server
.GetURL(
463 "server-redirect?files/title1.html"));
464 EXPECT_TRUE(NavigateIframeToURL(shell(),
465 server_redirect_http_url
, "test"));
466 // DidFailProvisionalLoad when navigating to https_url.
467 EXPECT_EQ(observer
.navigation_url(), https_url
);
468 EXPECT_FALSE(observer
.navigation_succeeded());
472 // Load same-site server-redirect page into Iframe,
473 // which redirects to cross-site page.
474 GURL
server_redirect_http_url(test_server()->GetURL(
475 "server-redirect?" + https_url
.spec()));
476 EXPECT_TRUE(NavigateIframeToURL(shell(),
477 server_redirect_http_url
, "test"));
479 EXPECT_EQ(observer
.navigation_url(), https_url
);
480 EXPECT_FALSE(observer
.navigation_succeeded());
484 // Load same-site client-redirect page into Iframe,
485 // which redirects to cross-site page.
486 GURL
client_redirect_http_url(test_server()->GetURL(
487 "client-redirect?" + https_url
.spec()));
489 RedirectNotificationObserver
load_observer2(
490 NOTIFICATION_LOAD_STOP
,
491 Source
<NavigationController
>(
492 &shell()->web_contents()->GetController()));
494 EXPECT_TRUE(NavigateIframeToURL(shell(),
495 client_redirect_http_url
, "test"));
497 // Same-site Client-Redirect Page should be loaded successfully.
498 EXPECT_EQ(observer
.navigation_url(), client_redirect_http_url
);
499 EXPECT_TRUE(observer
.navigation_succeeded());
501 // Redirecting to Cross-site Page should be blocked.
502 load_observer2
.Wait();
503 EXPECT_EQ(observer
.navigation_url(), https_url
);
504 EXPECT_FALSE(observer
.navigation_succeeded());
508 // Load same-site server-redirect page into Iframe,
509 // which redirects to same-site page.
510 GURL
server_redirect_http_url(test_server()->GetURL(
511 "server-redirect?files/title1.html"));
512 EXPECT_TRUE(NavigateIframeToURL(shell(),
513 server_redirect_http_url
, "test"));
514 EXPECT_EQ(observer
.navigation_url(), http_url
);
515 EXPECT_TRUE(observer
.navigation_succeeded());
519 // Load same-site client-redirect page into Iframe,
520 // which redirects to same-site page.
521 GURL
client_redirect_http_url(test_server()->GetURL(
522 "client-redirect?" + http_url
.spec()));
523 RedirectNotificationObserver
load_observer2(
524 NOTIFICATION_LOAD_STOP
,
525 Source
<NavigationController
>(
526 &shell()->web_contents()->GetController()));
528 EXPECT_TRUE(NavigateIframeToURL(shell(),
529 client_redirect_http_url
, "test"));
531 // Same-site Client-Redirect Page should be loaded successfully.
532 EXPECT_EQ(observer
.navigation_url(), client_redirect_http_url
);
533 EXPECT_TRUE(observer
.navigation_succeeded());
535 // Redirecting to Same-site Page should be loaded successfully.
536 load_observer2
.Wait();
537 EXPECT_EQ(observer
.navigation_url(), http_url
);
538 EXPECT_TRUE(observer
.navigation_succeeded());
542 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
543 // security checks are back in place.
544 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
545 // on Android (http://crbug.com/187570).
546 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
547 DISABLED_CrossSiteIframeRedirectTwice
) {
548 ASSERT_TRUE(test_server()->Start());
549 net::SpawnedTestServer
https_server(
550 net::SpawnedTestServer::TYPE_HTTPS
,
551 net::SpawnedTestServer::kLocalhost
,
552 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
553 ASSERT_TRUE(https_server
.Start());
555 GURL
main_url(test_server()->GetURL("files/site_per_process_main.html"));
556 GURL
http_url(test_server()->GetURL("files/title1.html"));
557 GURL
https_url(https_server
.GetURL("files/title1.html"));
559 NavigateToURL(shell(), main_url
);
561 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
563 // Load client-redirect page pointing to a cross-site client-redirect page,
564 // which eventually redirects back to same-site page.
565 GURL
client_redirect_https_url(https_server
.GetURL(
566 "client-redirect?" + http_url
.spec()));
567 GURL
client_redirect_http_url(test_server()->GetURL(
568 "client-redirect?" + client_redirect_https_url
.spec()));
570 // We should wait until second client redirect get cancelled.
571 RedirectNotificationObserver
load_observer2(
572 NOTIFICATION_LOAD_STOP
,
573 Source
<NavigationController
>(
574 &shell()->web_contents()->GetController()));
576 EXPECT_TRUE(NavigateIframeToURL(shell(), client_redirect_http_url
, "test"));
578 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
579 load_observer2
.Wait();
580 EXPECT_EQ(observer
.navigation_url(), client_redirect_https_url
);
581 EXPECT_FALSE(observer
.navigation_succeeded());
585 // Load server-redirect page pointing to a cross-site server-redirect page,
586 // which eventually redirect back to same-site page.
587 GURL
server_redirect_https_url(https_server
.GetURL(
588 "server-redirect?" + http_url
.spec()));
589 GURL
server_redirect_http_url(test_server()->GetURL(
590 "server-redirect?" + server_redirect_https_url
.spec()));
591 EXPECT_TRUE(NavigateIframeToURL(shell(),
592 server_redirect_http_url
, "test"));
593 EXPECT_EQ(observer
.navigation_url(), http_url
);
594 EXPECT_TRUE(observer
.navigation_succeeded());
598 // Load server-redirect page pointing to a cross-site server-redirect page,
599 // which eventually redirects back to cross-site page.
600 GURL
server_redirect_https_url(https_server
.GetURL(
601 "server-redirect?" + https_url
.spec()));
602 GURL
server_redirect_http_url(test_server()->GetURL(
603 "server-redirect?" + server_redirect_https_url
.spec()));
604 EXPECT_TRUE(NavigateIframeToURL(shell(), server_redirect_http_url
, "test"));
606 // DidFailProvisionalLoad when navigating to https_url.
607 EXPECT_EQ(observer
.navigation_url(), https_url
);
608 EXPECT_FALSE(observer
.navigation_succeeded());
612 // Load server-redirect page pointing to a cross-site client-redirect page,
613 // which eventually redirects back to same-site page.
614 GURL
client_redirect_http_url(https_server
.GetURL(
615 "client-redirect?" + http_url
.spec()));
616 GURL
server_redirect_http_url(test_server()->GetURL(
617 "server-redirect?" + client_redirect_http_url
.spec()));
618 EXPECT_TRUE(NavigateIframeToURL(shell(), server_redirect_http_url
, "test"));
620 // DidFailProvisionalLoad when navigating to client_redirect_http_url.
621 EXPECT_EQ(observer
.navigation_url(), client_redirect_http_url
);
622 EXPECT_FALSE(observer
.navigation_succeeded());
626 // Ensure that when navigating a frame cross-process RenderFrameProxyHosts are
627 // created in the FrameTree skipping the subtree of the navigating frame.
629 // Disabled on Mac due to flakiness on ASAN. http://crbug.com/425248
630 #if defined(OS_MACOSX)
631 #define MAYBE_ProxyCreationSkipsSubtree DISABLED_ProxyCreationSkipsSubtree
633 #define MAYBE_ProxyCreationSkipsSubtree ProxyCreationSkipsSubtree
635 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest
,
636 MAYBE_ProxyCreationSkipsSubtree
) {
637 GURL
main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
638 NavigateToURL(shell(), main_url
);
640 // It is safe to obtain the root frame tree node here, as it doesn't change.
641 FrameTreeNode
* root
=
642 static_cast<WebContentsImpl
*>(shell()->web_contents())->
643 GetFrameTree()->root();
645 EXPECT_TRUE(root
->child_at(1) != NULL
);
646 EXPECT_EQ(2U, root
->child_at(1)->child_count());
649 // Load same-site page into iframe.
650 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
651 GURL
http_url(embedded_test_server()->GetURL("/title1.html"));
652 NavigateFrameToURL(root
->child_at(0), http_url
);
653 EXPECT_EQ(http_url
, observer
.navigation_url());
654 EXPECT_TRUE(observer
.navigation_succeeded());
655 RenderFrameProxyHost
* proxy_to_parent
=
656 root
->child_at(0)->render_manager()->GetRenderFrameProxyHost(
657 shell()->web_contents()->GetSiteInstance());
658 EXPECT_FALSE(proxy_to_parent
);
661 // Create the cross-site URL to navigate to.
662 GURL cross_site_url
=
663 embedded_test_server()->GetURL("foo.com", "/frame_tree/1-1.html");
665 // Load cross-site page into the second iframe without waiting for the
666 // navigation to complete. Once LoadURLWithParams returns, we would expect
667 // proxies to have been created in the frame tree, but children of the
668 // navigating frame to still be present. The reason is that we don't run the
669 // message loop, so no IPCs that alter the frame tree can be processed.
670 FrameTreeNode
* child
= root
->child_at(1);
671 SiteInstance
* site
= NULL
;
673 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
674 TestFrameNavigationObserver
navigation_observer(child
);
675 NavigationController::LoadURLParams
params(cross_site_url
);
676 params
.transition_type
= PageTransitionFromInt(ui::PAGE_TRANSITION_LINK
);
677 params
.frame_tree_node_id
= child
->frame_tree_node_id();
678 child
->navigator()->GetController()->LoadURLWithParams(params
);
679 EXPECT_TRUE(child
->render_manager()->pending_frame_host());
681 site
= child
->render_manager()->pending_frame_host()->GetSiteInstance();
682 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site
);
684 EXPECT_TRUE(root
->render_manager()->GetRenderFrameProxyHost(site
));
686 root
->child_at(0)->render_manager()->GetRenderFrameProxyHost(site
));
687 EXPECT_FALSE(child
->render_manager()->GetRenderFrameProxyHost(site
));
688 for (size_t i
= 0; i
< child
->child_count(); ++i
) {
690 child
->child_at(i
)->render_manager()->GetRenderFrameProxyHost(site
));
692 // Now that the verification is done, run the message loop and wait for the
693 // navigation to complete.
694 navigation_observer
.Wait();
695 EXPECT_FALSE(child
->render_manager()->pending_frame_host());
696 EXPECT_TRUE(observer
.navigation_succeeded());
697 EXPECT_EQ(cross_site_url
, observer
.navigation_url());
700 // Load another cross-site page into the same iframe.
701 cross_site_url
= embedded_test_server()->GetURL("bar.com", "/title2.html");
703 // Perform the same checks as the first cross-site navigation, since
704 // there have been issues in subsequent cross-site navigations. Also ensure
705 // that the SiteInstance has properly changed.
706 // TODO(nasko): Once we have proper cleanup of resources, add code to
707 // verify that the intermediate SiteInstance/RenderFrameHost have been
708 // properly cleaned up.
709 SitePerProcessWebContentsObserver
observer(shell()->web_contents());
710 TestFrameNavigationObserver
navigation_observer(child
);
711 NavigationController::LoadURLParams
params(cross_site_url
);
712 params
.transition_type
= PageTransitionFromInt(ui::PAGE_TRANSITION_LINK
);
713 params
.frame_tree_node_id
= child
->frame_tree_node_id();
714 child
->navigator()->GetController()->LoadURLWithParams(params
);
715 EXPECT_TRUE(child
->render_manager()->pending_frame_host() != NULL
);
717 SiteInstance
* site2
=
718 child
->render_manager()->pending_frame_host()->GetSiteInstance();
719 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site2
);
720 EXPECT_NE(site
, site2
);
722 EXPECT_TRUE(root
->render_manager()->GetRenderFrameProxyHost(site2
));
724 root
->child_at(0)->render_manager()->GetRenderFrameProxyHost(site2
));
725 EXPECT_FALSE(child
->render_manager()->GetRenderFrameProxyHost(site2
));
726 for (size_t i
= 0; i
< child
->child_count(); ++i
) {
728 child
->child_at(i
)->render_manager()->GetRenderFrameProxyHost(site2
));
731 navigation_observer
.Wait();
732 EXPECT_TRUE(observer
.navigation_succeeded());
733 EXPECT_EQ(cross_site_url
, observer
.navigation_url());
734 EXPECT_EQ(0U, child
->child_count());
738 } // namespace content