Chromecast: extracts Linux window creation code to a common place.
[chromium-blink-merge.git] / content / browser / site_per_process_browsertest.cc
bloba0a459ea82ff7cbade6e5954d281926fe73f41c9
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"
30 namespace content {
32 class SitePerProcessWebContentsObserver: public WebContentsObserver {
33 public:
34 explicit SitePerProcessWebContentsObserver(WebContents* web_contents)
35 : WebContentsObserver(web_contents),
36 navigation_succeeded_(false) {}
37 virtual ~SitePerProcessWebContentsObserver() {}
39 virtual void DidStartProvisionalLoadForFrame(
40 RenderFrameHost* render_frame_host,
41 const GURL& validated_url,
42 bool is_error_page,
43 bool is_iframe_srcdoc) override {
44 navigation_succeeded_ = false;
47 virtual void DidFailProvisionalLoad(
48 RenderFrameHost* render_frame_host,
49 const GURL& validated_url,
50 int error_code,
51 const base::string16& error_description) override {
52 navigation_url_ = validated_url;
53 navigation_succeeded_ = false;
56 virtual void DidCommitProvisionalLoadForFrame(
57 RenderFrameHost* render_frame_host,
58 const GURL& url,
59 ui::PageTransition transition_type) override {
60 navigation_url_ = url;
61 navigation_succeeded_ = true;
64 const GURL& navigation_url() const {
65 return navigation_url_;
68 int navigation_succeeded() const { return navigation_succeeded_; }
70 private:
71 GURL navigation_url_;
72 bool navigation_succeeded_;
74 DISALLOW_COPY_AND_ASSIGN(SitePerProcessWebContentsObserver);
77 class RedirectNotificationObserver : public NotificationObserver {
78 public:
79 // Register to listen for notifications of the given type from either a
80 // specific source, or from all sources if |source| is
81 // NotificationService::AllSources().
82 RedirectNotificationObserver(int notification_type,
83 const NotificationSource& source);
84 virtual ~RedirectNotificationObserver();
86 // Wait until the specified notification occurs. If the notification was
87 // emitted between the construction of this object and this call then it
88 // returns immediately.
89 void Wait();
91 // Returns NotificationService::AllSources() if we haven't observed a
92 // notification yet.
93 const NotificationSource& source() const {
94 return source_;
97 const NotificationDetails& details() const {
98 return details_;
101 // NotificationObserver:
102 virtual void Observe(int type,
103 const NotificationSource& source,
104 const NotificationDetails& details) override;
106 private:
107 bool seen_;
108 bool seen_twice_;
109 bool running_;
110 NotificationRegistrar registrar_;
112 NotificationSource source_;
113 NotificationDetails details_;
114 scoped_refptr<MessageLoopRunner> message_loop_runner_;
116 DISALLOW_COPY_AND_ASSIGN(RedirectNotificationObserver);
119 RedirectNotificationObserver::RedirectNotificationObserver(
120 int notification_type,
121 const NotificationSource& source)
122 : seen_(false),
123 running_(false),
124 source_(NotificationService::AllSources()) {
125 registrar_.Add(this, notification_type, source);
128 RedirectNotificationObserver::~RedirectNotificationObserver() {}
130 void RedirectNotificationObserver::Wait() {
131 if (seen_ && seen_twice_)
132 return;
134 running_ = true;
135 message_loop_runner_ = new MessageLoopRunner;
136 message_loop_runner_->Run();
137 EXPECT_TRUE(seen_);
140 void RedirectNotificationObserver::Observe(
141 int type,
142 const NotificationSource& source,
143 const NotificationDetails& details) {
144 source_ = source;
145 details_ = details;
146 seen_twice_ = seen_;
147 seen_ = true;
148 if (!running_)
149 return;
151 message_loop_runner_->Quit();
152 running_ = false;
156 // SitePerProcessBrowserTest
159 SitePerProcessBrowserTest::SitePerProcessBrowserTest() {
162 void SitePerProcessBrowserTest::StartFrameAtDataURL() {
163 std::string data_url_script =
164 "var iframes = document.getElementById('test');iframes.src="
165 "'data:text/html,dataurl';";
166 ASSERT_TRUE(ExecuteScript(shell()->web_contents(), data_url_script));
169 bool SitePerProcessBrowserTest::NavigateIframeToURL(Shell* window,
170 const GURL& url,
171 std::string iframe_id) {
172 // TODO(creis): This should wait for LOAD_STOP, but cross-site subframe
173 // navigations generate extra DidStartLoading and DidStopLoading messages.
174 // Until we replace swappedout:// with frame proxies, we need to listen for
175 // something else. For now, we trigger NEW_SUBFRAME navigations and listen
176 // for commit.
177 std::string script = base::StringPrintf(
178 "setTimeout(\""
179 "var iframes = document.getElementById('%s');iframes.src='%s';"
180 "\",0)",
181 iframe_id.c_str(), url.spec().c_str());
182 WindowedNotificationObserver load_observer(
183 NOTIFICATION_NAV_ENTRY_COMMITTED,
184 Source<NavigationController>(
185 &window->web_contents()->GetController()));
186 bool result = ExecuteScript(window->web_contents(), script);
187 load_observer.Wait();
188 return result;
191 void SitePerProcessBrowserTest::SetUpCommandLine(CommandLine* command_line) {
192 command_line->AppendSwitch(switches::kSitePerProcess);
195 void SitePerProcessBrowserTest::SetUpOnMainThread() {
196 host_resolver()->AddRule("*", "127.0.0.1");
197 ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
198 SetupCrossSiteRedirector(embedded_test_server());
199 embedded_test_server()->ServeFilesFromDirectory(GetTestFilePath("files", ""));
202 // It fails on ChromeOS and Android, so disabled while investigating.
203 // http://crbug.com/399775
204 #if defined(OS_ANDROID) || defined(OS_CHROMEOS)
205 #define MAYBE_CrossSiteIframe DISABLED_CrossSiteIframe
206 #else
207 #define MAYBE_CrossSiteIframe CrossSiteIframe
208 #endif
209 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_CrossSiteIframe) {
210 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
211 NavigateToURL(shell(), main_url);
213 // It is safe to obtain the root frame tree node here, as it doesn't change.
214 FrameTreeNode* root =
215 static_cast<WebContentsImpl*>(shell()->web_contents())->
216 GetFrameTree()->root();
218 SitePerProcessWebContentsObserver observer(shell()->web_contents());
220 // Load same-site page into iframe.
221 FrameTreeNode* child = root->child_at(0);
222 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
223 NavigateFrameToURL(child, http_url);
224 EXPECT_EQ(http_url, observer.navigation_url());
225 EXPECT_TRUE(observer.navigation_succeeded());
227 // There should be only one RenderWidgetHost when there are no
228 // cross-process iframes.
229 std::set<RenderWidgetHostView*> views_set =
230 static_cast<WebContentsImpl*>(shell()->web_contents())
231 ->GetRenderWidgetHostViewsInTree();
232 EXPECT_EQ(1U, views_set.size());
234 RenderFrameProxyHost* proxy_to_parent =
235 child->render_manager()->GetRenderFrameProxyHost(
236 shell()->web_contents()->GetSiteInstance());
237 EXPECT_FALSE(proxy_to_parent);
239 // Load cross-site page into iframe.
240 NavigateFrameToURL(
241 root->child_at(0),
242 embedded_test_server()->GetURL("/cross-site/foo.com/title2.html"));
243 // Verify that the navigation succeeded and the expected URL was loaded.
244 EXPECT_TRUE(observer.navigation_succeeded());
245 EXPECT_EQ(embedded_test_server()->base_url().scheme(),
246 observer.navigation_url().scheme());
247 EXPECT_EQ("foo.com", observer.navigation_url().host());
248 EXPECT_EQ("/title2.html", observer.navigation_url().path());
250 // Ensure that we have created a new process for the subframe.
251 ASSERT_EQ(2U, root->child_count());
252 SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
253 RenderViewHost* rvh = child->current_frame_host()->render_view_host();
254 RenderProcessHost* rph = child->current_frame_host()->GetProcess();
255 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh);
256 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
257 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), rph);
259 // There should be now two RenderWidgetHosts, one for each process
260 // rendering a frame.
261 std::set<RenderWidgetHostView*> views_set =
262 static_cast<WebContentsImpl*>(shell()->web_contents())
263 ->GetRenderWidgetHostViewsInTree();
264 EXPECT_EQ(2U, views_set.size());
266 proxy_to_parent = child->render_manager()->GetProxyToParent();
267 EXPECT_TRUE(proxy_to_parent);
268 EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
269 EXPECT_EQ(
270 rvh->GetView(),
271 proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
273 // Load another cross-site page into the same iframe.
274 NavigateFrameToURL(
275 root->child_at(0),
276 embedded_test_server()->GetURL("/cross-site/bar.com/title3.html"));
277 EXPECT_TRUE(observer.navigation_succeeded());
278 EXPECT_EQ(embedded_test_server()->base_url().scheme(),
279 observer.navigation_url().scheme());
280 EXPECT_EQ("bar.com", observer.navigation_url().host());
281 EXPECT_EQ("/title3.html", observer.navigation_url().path());
283 // Check again that a new process is created and is different from the
284 // top level one and the previous one.
285 ASSERT_EQ(2U, root->child_count());
286 child = root->child_at(0);
287 EXPECT_NE(shell()->web_contents()->GetRenderViewHost(),
288 child->current_frame_host()->render_view_host());
289 EXPECT_NE(rvh, child->current_frame_host()->render_view_host());
290 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
291 child->current_frame_host()->GetSiteInstance());
292 EXPECT_NE(site_instance,
293 child->current_frame_host()->GetSiteInstance());
294 EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(),
295 child->current_frame_host()->GetProcess());
296 EXPECT_NE(rph, child->current_frame_host()->GetProcess());
298 std::set<RenderWidgetHostView*> views_set =
299 static_cast<WebContentsImpl*>(shell()->web_contents())
300 ->GetRenderWidgetHostViewsInTree();
301 EXPECT_EQ(2U, views_set.size());
303 EXPECT_EQ(proxy_to_parent, child->render_manager()->GetProxyToParent());
304 EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
305 EXPECT_EQ(
306 child->current_frame_host()->render_view_host()->GetView(),
307 proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
310 // It fails on ChromeOS and Android, so disabled while investigating.
311 // http://crbug.com/399775
312 #if defined(OS_ANDROID) || defined(OS_CHROMEOS)
313 #define MAYBE_NavigateRemoteFrame DISABLED_NavigateRemoteFrame
314 #else
315 #define MAYBE_NavigateRemoteFrame NavigateRemoteFrame
316 #endif
317 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_NavigateRemoteFrame) {
318 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
319 NavigateToURL(shell(), main_url);
321 // It is safe to obtain the root frame tree node here, as it doesn't change.
322 FrameTreeNode* root =
323 static_cast<WebContentsImpl*>(shell()->web_contents())->
324 GetFrameTree()->root();
326 SitePerProcessWebContentsObserver observer(shell()->web_contents());
328 // Load same-site page into iframe.
329 FrameTreeNode* child = root->child_at(0);
330 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
331 NavigateFrameToURL(child, http_url);
332 EXPECT_EQ(http_url, observer.navigation_url());
333 EXPECT_TRUE(observer.navigation_succeeded());
335 // Load cross-site page into iframe.
336 NavigateFrameToURL(
337 root->child_at(0),
338 embedded_test_server()->GetURL("/cross-site/foo.com/title2.html"));
339 EXPECT_TRUE(observer.navigation_succeeded());
340 EXPECT_EQ("foo.com", observer.navigation_url().host());
341 EXPECT_EQ("/title2.html", observer.navigation_url().path());
343 // Ensure that we have created a new process for the subframe.
344 ASSERT_EQ(2U, root->child_count());
345 SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
346 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
348 // Emulate the main frame changing the src of the iframe such that it
349 // navigates cross-site.
350 NavigateIframeToURL(
351 shell(),
352 embedded_test_server()->GetURL("/cross-site/bar.com/title3.html"),
353 "test");
354 EXPECT_TRUE(observer.navigation_succeeded());
355 EXPECT_EQ("bar.com", observer.navigation_url().host());
356 EXPECT_EQ("/title3.html", observer.navigation_url().path());
358 // Check again that a new process is created and is different from the
359 // top level one and the previous one.
360 ASSERT_EQ(2U, root->child_count());
361 child = root->child_at(0);
362 EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
363 child->current_frame_host()->GetSiteInstance());
364 EXPECT_NE(site_instance,
365 child->current_frame_host()->GetSiteInstance());
367 // TODO(japhet): This currently causes an assertion in the renderer process.
368 // Enable when the assertion is fixed.
369 //NavigateFrameToURL(child, http_url);
370 //EXPECT_EQ(http_url, observer.navigation_url());
371 //EXPECT_TRUE(observer.navigation_succeeded());
372 //EXPECT_EQ(shell()->web_contents()->GetSiteInstance(),
373 // child->current_frame_host()->GetSiteInstance());
376 // Crash a subframe and ensures its children are cleared from the FrameTree.
377 // See http://crbug.com/338508.
378 // TODO(creis): Disabled for flakiness; see http://crbug.com/405582.
379 // TODO(creis): Enable this on Android when we can kill the process there.
380 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DISABLED_CrashSubframe) {
381 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
382 NavigateToURL(shell(), main_url);
384 StartFrameAtDataURL();
386 // These must stay in scope with replace_host.
387 GURL::Replacements replace_host;
388 std::string foo_com("foo.com");
390 // Load cross-site page into iframe.
391 EXPECT_TRUE(NavigateIframeToURL(
392 shell(),
393 embedded_test_server()->GetURL("/cross-site/foo.com/title2.html"),
394 "test"));
396 // Check the subframe process.
397 FrameTreeNode* root =
398 static_cast<WebContentsImpl*>(shell()->web_contents())->
399 GetFrameTree()->root();
400 ASSERT_EQ(1U, root->child_count());
401 FrameTreeNode* child = root->child_at(0);
402 EXPECT_EQ(main_url, root->current_url());
403 EXPECT_EQ("foo.com", child->current_url().host());
404 EXPECT_EQ("/title2.html", child->current_url().path());
406 EXPECT_TRUE(
407 child->current_frame_host()->render_view_host()->IsRenderViewLive());
408 EXPECT_TRUE(child->current_frame_host()->IsRenderFrameLive());
410 // Crash the subframe process.
411 RenderProcessHost* root_process = root->current_frame_host()->GetProcess();
412 RenderProcessHost* child_process = child->current_frame_host()->GetProcess();
414 RenderProcessHostWatcher crash_observer(
415 child_process,
416 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
417 base::KillProcess(child_process->GetHandle(), 0, false);
418 crash_observer.Wait();
421 // Ensure that the child frame still exists but has been cleared.
422 EXPECT_EQ(1U, root->child_count());
423 EXPECT_EQ(main_url, root->current_url());
424 EXPECT_EQ(GURL(), child->current_url());
426 EXPECT_FALSE(
427 child->current_frame_host()->render_view_host()->IsRenderViewLive());
428 EXPECT_FALSE(child->current_frame_host()->IsRenderFrameLive());
429 EXPECT_FALSE(child->current_frame_host()->render_frame_created_);
431 // Now crash the top-level page to clear the child frame.
433 RenderProcessHostWatcher crash_observer(
434 root_process,
435 RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
436 base::KillProcess(root_process->GetHandle(), 0, false);
437 crash_observer.Wait();
439 EXPECT_EQ(0U, root->child_count());
440 EXPECT_EQ(GURL(), root->current_url());
443 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
444 // security checks are back in place.
445 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
446 // on Android (http://crbug.com/187570).
447 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
448 DISABLED_CrossSiteIframeRedirectOnce) {
449 ASSERT_TRUE(test_server()->Start());
450 net::SpawnedTestServer https_server(
451 net::SpawnedTestServer::TYPE_HTTPS,
452 net::SpawnedTestServer::kLocalhost,
453 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
454 ASSERT_TRUE(https_server.Start());
456 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
457 GURL http_url(test_server()->GetURL("files/title1.html"));
458 GURL https_url(https_server.GetURL("files/title1.html"));
460 NavigateToURL(shell(), main_url);
462 SitePerProcessWebContentsObserver observer(shell()->web_contents());
464 // Load cross-site client-redirect page into Iframe.
465 // Should be blocked.
466 GURL client_redirect_https_url(https_server.GetURL(
467 "client-redirect?files/title1.html"));
468 EXPECT_TRUE(NavigateIframeToURL(shell(),
469 client_redirect_https_url, "test"));
470 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
471 EXPECT_EQ(observer.navigation_url(), client_redirect_https_url);
472 EXPECT_FALSE(observer.navigation_succeeded());
476 // Load cross-site server-redirect page into Iframe,
477 // which redirects to same-site page.
478 GURL server_redirect_http_url(https_server.GetURL(
479 "server-redirect?" + http_url.spec()));
480 EXPECT_TRUE(NavigateIframeToURL(shell(),
481 server_redirect_http_url, "test"));
482 EXPECT_EQ(observer.navigation_url(), http_url);
483 EXPECT_TRUE(observer.navigation_succeeded());
487 // Load cross-site server-redirect page into Iframe,
488 // which redirects to cross-site page.
489 GURL server_redirect_http_url(https_server.GetURL(
490 "server-redirect?files/title1.html"));
491 EXPECT_TRUE(NavigateIframeToURL(shell(),
492 server_redirect_http_url, "test"));
493 // DidFailProvisionalLoad when navigating to https_url.
494 EXPECT_EQ(observer.navigation_url(), https_url);
495 EXPECT_FALSE(observer.navigation_succeeded());
499 // Load same-site server-redirect page into Iframe,
500 // which redirects to cross-site page.
501 GURL server_redirect_http_url(test_server()->GetURL(
502 "server-redirect?" + https_url.spec()));
503 EXPECT_TRUE(NavigateIframeToURL(shell(),
504 server_redirect_http_url, "test"));
506 EXPECT_EQ(observer.navigation_url(), https_url);
507 EXPECT_FALSE(observer.navigation_succeeded());
511 // Load same-site client-redirect page into Iframe,
512 // which redirects to cross-site page.
513 GURL client_redirect_http_url(test_server()->GetURL(
514 "client-redirect?" + https_url.spec()));
516 RedirectNotificationObserver load_observer2(
517 NOTIFICATION_LOAD_STOP,
518 Source<NavigationController>(
519 &shell()->web_contents()->GetController()));
521 EXPECT_TRUE(NavigateIframeToURL(shell(),
522 client_redirect_http_url, "test"));
524 // Same-site Client-Redirect Page should be loaded successfully.
525 EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
526 EXPECT_TRUE(observer.navigation_succeeded());
528 // Redirecting to Cross-site Page should be blocked.
529 load_observer2.Wait();
530 EXPECT_EQ(observer.navigation_url(), https_url);
531 EXPECT_FALSE(observer.navigation_succeeded());
535 // Load same-site server-redirect page into Iframe,
536 // which redirects to same-site page.
537 GURL server_redirect_http_url(test_server()->GetURL(
538 "server-redirect?files/title1.html"));
539 EXPECT_TRUE(NavigateIframeToURL(shell(),
540 server_redirect_http_url, "test"));
541 EXPECT_EQ(observer.navigation_url(), http_url);
542 EXPECT_TRUE(observer.navigation_succeeded());
546 // Load same-site client-redirect page into Iframe,
547 // which redirects to same-site page.
548 GURL client_redirect_http_url(test_server()->GetURL(
549 "client-redirect?" + http_url.spec()));
550 RedirectNotificationObserver load_observer2(
551 NOTIFICATION_LOAD_STOP,
552 Source<NavigationController>(
553 &shell()->web_contents()->GetController()));
555 EXPECT_TRUE(NavigateIframeToURL(shell(),
556 client_redirect_http_url, "test"));
558 // Same-site Client-Redirect Page should be loaded successfully.
559 EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
560 EXPECT_TRUE(observer.navigation_succeeded());
562 // Redirecting to Same-site Page should be loaded successfully.
563 load_observer2.Wait();
564 EXPECT_EQ(observer.navigation_url(), http_url);
565 EXPECT_TRUE(observer.navigation_succeeded());
569 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
570 // security checks are back in place.
571 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
572 // on Android (http://crbug.com/187570).
573 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
574 DISABLED_CrossSiteIframeRedirectTwice) {
575 ASSERT_TRUE(test_server()->Start());
576 net::SpawnedTestServer https_server(
577 net::SpawnedTestServer::TYPE_HTTPS,
578 net::SpawnedTestServer::kLocalhost,
579 base::FilePath(FILE_PATH_LITERAL("content/test/data")));
580 ASSERT_TRUE(https_server.Start());
582 GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
583 GURL http_url(test_server()->GetURL("files/title1.html"));
584 GURL https_url(https_server.GetURL("files/title1.html"));
586 NavigateToURL(shell(), main_url);
588 SitePerProcessWebContentsObserver observer(shell()->web_contents());
590 // Load client-redirect page pointing to a cross-site client-redirect page,
591 // which eventually redirects back to same-site page.
592 GURL client_redirect_https_url(https_server.GetURL(
593 "client-redirect?" + http_url.spec()));
594 GURL client_redirect_http_url(test_server()->GetURL(
595 "client-redirect?" + client_redirect_https_url.spec()));
597 // We should wait until second client redirect get cancelled.
598 RedirectNotificationObserver load_observer2(
599 NOTIFICATION_LOAD_STOP,
600 Source<NavigationController>(
601 &shell()->web_contents()->GetController()));
603 EXPECT_TRUE(NavigateIframeToURL(shell(), client_redirect_http_url, "test"));
605 // DidFailProvisionalLoad when navigating to client_redirect_https_url.
606 load_observer2.Wait();
607 EXPECT_EQ(observer.navigation_url(), client_redirect_https_url);
608 EXPECT_FALSE(observer.navigation_succeeded());
612 // Load server-redirect page pointing to a cross-site server-redirect page,
613 // which eventually redirect back to same-site page.
614 GURL server_redirect_https_url(https_server.GetURL(
615 "server-redirect?" + http_url.spec()));
616 GURL server_redirect_http_url(test_server()->GetURL(
617 "server-redirect?" + server_redirect_https_url.spec()));
618 EXPECT_TRUE(NavigateIframeToURL(shell(),
619 server_redirect_http_url, "test"));
620 EXPECT_EQ(observer.navigation_url(), http_url);
621 EXPECT_TRUE(observer.navigation_succeeded());
625 // Load server-redirect page pointing to a cross-site server-redirect page,
626 // which eventually redirects back to cross-site page.
627 GURL server_redirect_https_url(https_server.GetURL(
628 "server-redirect?" + https_url.spec()));
629 GURL server_redirect_http_url(test_server()->GetURL(
630 "server-redirect?" + server_redirect_https_url.spec()));
631 EXPECT_TRUE(NavigateIframeToURL(shell(), server_redirect_http_url, "test"));
633 // DidFailProvisionalLoad when navigating to https_url.
634 EXPECT_EQ(observer.navigation_url(), https_url);
635 EXPECT_FALSE(observer.navigation_succeeded());
639 // Load server-redirect page pointing to a cross-site client-redirect page,
640 // which eventually redirects back to same-site page.
641 GURL client_redirect_http_url(https_server.GetURL(
642 "client-redirect?" + http_url.spec()));
643 GURL server_redirect_http_url(test_server()->GetURL(
644 "server-redirect?" + client_redirect_http_url.spec()));
645 EXPECT_TRUE(NavigateIframeToURL(shell(), server_redirect_http_url, "test"));
647 // DidFailProvisionalLoad when navigating to client_redirect_http_url.
648 EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
649 EXPECT_FALSE(observer.navigation_succeeded());
653 // Ensure that when navigating a frame cross-process RenderFrameProxyHosts are
654 // created in the FrameTree skipping the subtree of the navigating frame.
655 // TODO(nasko): Test is disabled on Android, because it times out. It should
656 // be fixed together with CrossSiteIframe on that platform.
658 // Disabled on Mac due to flakiness on ASAN. http://crbug.com/425248
659 #if defined(OS_ANDROID) || defined(OS_MACOSX)
660 #define MAYBE_ProxyCreationSkipsSubtree DISABLED_ProxyCreationSkipsSubtree
661 #else
662 #define MAYBE_ProxyCreationSkipsSubtree ProxyCreationSkipsSubtree
663 #endif
664 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
665 MAYBE_ProxyCreationSkipsSubtree) {
666 GURL main_url(embedded_test_server()->GetURL("/site_per_process_main.html"));
667 NavigateToURL(shell(), main_url);
669 // It is safe to obtain the root frame tree node here, as it doesn't change.
670 FrameTreeNode* root =
671 static_cast<WebContentsImpl*>(shell()->web_contents())->
672 GetFrameTree()->root();
674 EXPECT_TRUE(root->child_at(1) != NULL);
675 EXPECT_EQ(2U, root->child_at(1)->child_count());
678 // Load same-site page into iframe.
679 SitePerProcessWebContentsObserver observer(shell()->web_contents());
680 GURL http_url(embedded_test_server()->GetURL("/title1.html"));
681 NavigateFrameToURL(root->child_at(0), http_url);
682 EXPECT_EQ(http_url, observer.navigation_url());
683 EXPECT_TRUE(observer.navigation_succeeded());
684 RenderFrameProxyHost* proxy_to_parent =
685 root->child_at(0)->render_manager()->GetRenderFrameProxyHost(
686 shell()->web_contents()->GetSiteInstance());
687 EXPECT_FALSE(proxy_to_parent);
690 // Create the cross-site URL to navigate to.
691 GURL::Replacements replace_host;
692 std::string foo_com("foo.com");
693 GURL cross_site_url(embedded_test_server()->GetURL("/frame_tree/1-1.html"));
694 replace_host.SetHostStr(foo_com);
695 cross_site_url = cross_site_url.ReplaceComponents(replace_host);
697 // Load cross-site page into the second iframe without waiting for the
698 // navigation to complete. Once LoadURLWithParams returns, we would expect
699 // proxies to have been created in the frame tree, but children of the
700 // navigating frame to still be present. The reason is that we don't run the
701 // message loop, so no IPCs that alter the frame tree can be processed.
702 FrameTreeNode* child = root->child_at(1);
703 SiteInstance* site = NULL;
705 SitePerProcessWebContentsObserver observer(shell()->web_contents());
706 TestFrameNavigationObserver navigation_observer(child);
707 NavigationController::LoadURLParams params(cross_site_url);
708 params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
709 params.frame_tree_node_id = child->frame_tree_node_id();
710 child->navigator()->GetController()->LoadURLWithParams(params);
711 EXPECT_TRUE(child->render_manager()->pending_frame_host());
713 site = child->render_manager()->pending_frame_host()->GetSiteInstance();
714 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site);
716 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(site));
717 EXPECT_TRUE(
718 root->child_at(0)->render_manager()->GetRenderFrameProxyHost(site));
719 EXPECT_FALSE(child->render_manager()->GetRenderFrameProxyHost(site));
720 for (size_t i = 0; i < child->child_count(); ++i) {
721 EXPECT_FALSE(
722 child->child_at(i)->render_manager()->GetRenderFrameProxyHost(site));
724 // Now that the verification is done, run the message loop and wait for the
725 // navigation to complete.
726 navigation_observer.Wait();
727 EXPECT_FALSE(child->render_manager()->pending_frame_host());
728 EXPECT_EQ(cross_site_url, observer.navigation_url());
729 EXPECT_TRUE(observer.navigation_succeeded());
732 // Load another cross-site page into the same iframe.
733 cross_site_url = embedded_test_server()->GetURL("/title2.html");
734 std::string bar_com("bar.com");
735 replace_host.SetHostStr(bar_com);
736 cross_site_url = cross_site_url.ReplaceComponents(replace_host);
739 // Perform the same checks as the first cross-site navigation, since
740 // there have been issues in subsequent cross-site navigations. Also ensure
741 // that the SiteInstance has properly changed.
742 // TODO(nasko): Once we have proper cleanup of resources, add code to
743 // verify that the intermediate SiteInstance/RenderFrameHost have been
744 // properly cleaned up.
745 SitePerProcessWebContentsObserver observer(shell()->web_contents());
746 TestFrameNavigationObserver navigation_observer(child);
747 NavigationController::LoadURLParams params(cross_site_url);
748 params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_LINK);
749 params.frame_tree_node_id = child->frame_tree_node_id();
750 child->navigator()->GetController()->LoadURLWithParams(params);
751 EXPECT_TRUE(child->render_manager()->pending_frame_host() != NULL);
753 SiteInstance* site2 =
754 child->render_manager()->pending_frame_host()->GetSiteInstance();
755 EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site2);
756 EXPECT_NE(site, site2);
758 EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(site2));
759 EXPECT_TRUE(
760 root->child_at(0)->render_manager()->GetRenderFrameProxyHost(site2));
761 EXPECT_FALSE(child->render_manager()->GetRenderFrameProxyHost(site2));
762 for (size_t i = 0; i < child->child_count(); ++i) {
763 EXPECT_FALSE(
764 child->child_at(i)->render_manager()->GetRenderFrameProxyHost(site2));
767 navigation_observer.Wait();
768 EXPECT_EQ(cross_site_url, observer.navigation_url());
769 EXPECT_TRUE(observer.navigation_succeeded());
770 EXPECT_EQ(0U, child->child_count());
774 } // namespace content