Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / content / browser / site_per_process_browsertest.cc
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.
4
5 #include "content/browser/site_per_process_browsertest.h"
6
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"
29
30 namespace content {
31
32 class SitePerProcessWebContentsObserver: public WebContentsObserver {
33  public:
34   explicit SitePerProcessWebContentsObserver(WebContents* web_contents)
35       : WebContentsObserver(web_contents),
36         navigation_succeeded_(false) {}
37   ~SitePerProcessWebContentsObserver() override {}
38
39   void DidStartProvisionalLoadForFrame(RenderFrameHost* render_frame_host,
40                                        const GURL& validated_url,
41                                        bool is_error_page,
42                                        bool is_iframe_srcdoc) override {
43     navigation_succeeded_ = false;
44   }
45
46   void DidFailProvisionalLoad(
47       RenderFrameHost* render_frame_host,
48       const GURL& validated_url,
49       int error_code,
50       const base::string16& error_description) override {
51     navigation_url_ = validated_url;
52     navigation_succeeded_ = false;
53   }
54
55   void DidCommitProvisionalLoadForFrame(
56       RenderFrameHost* render_frame_host,
57       const GURL& url,
58       ui::PageTransition transition_type) override {
59     navigation_url_ = url;
60     navigation_succeeded_ = true;
61   }
62
63   const GURL& navigation_url() const {
64     return navigation_url_;
65   }
66
67   int navigation_succeeded() const { return navigation_succeeded_; }
68
69  private:
70   GURL navigation_url_;
71   bool navigation_succeeded_;
72
73   DISALLOW_COPY_AND_ASSIGN(SitePerProcessWebContentsObserver);
74 };
75
76 class RedirectNotificationObserver : public NotificationObserver {
77  public:
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;
84
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.
88   void Wait();
89
90   // Returns NotificationService::AllSources() if we haven't observed a
91   // notification yet.
92   const NotificationSource& source() const {
93     return source_;
94   }
95
96   const NotificationDetails& details() const {
97     return details_;
98   }
99
100   // NotificationObserver:
101   void Observe(int type,
102                const NotificationSource& source,
103                const NotificationDetails& details) override;
104
105  private:
106   bool seen_;
107   bool seen_twice_;
108   bool running_;
109   NotificationRegistrar registrar_;
110
111   NotificationSource source_;
112   NotificationDetails details_;
113   scoped_refptr<MessageLoopRunner> message_loop_runner_;
114
115   DISALLOW_COPY_AND_ASSIGN(RedirectNotificationObserver);
116 };
117
118 RedirectNotificationObserver::RedirectNotificationObserver(
119     int notification_type,
120     const NotificationSource& source)
121     : seen_(false),
122       running_(false),
123       source_(NotificationService::AllSources()) {
124   registrar_.Add(this, notification_type, source);
125 }
126
127 RedirectNotificationObserver::~RedirectNotificationObserver() {}
128
129 void RedirectNotificationObserver::Wait() {
130   if (seen_ && seen_twice_)
131     return;
132
133   running_ = true;
134   message_loop_runner_ = new MessageLoopRunner;
135   message_loop_runner_->Run();
136   EXPECT_TRUE(seen_);
137 }
138
139 void RedirectNotificationObserver::Observe(
140     int type,
141     const NotificationSource& source,
142     const NotificationDetails& details) {
143   source_ = source;
144   details_ = details;
145   seen_twice_ = seen_;
146   seen_ = true;
147   if (!running_)
148     return;
149
150   message_loop_runner_->Quit();
151   running_ = false;
152 }
153
154 //
155 // SitePerProcessBrowserTest
156 //
157
158 SitePerProcessBrowserTest::SitePerProcessBrowserTest() {
159 };
160
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));
166 }
167
168 bool SitePerProcessBrowserTest::NavigateIframeToURL(Shell* window,
169                                                     const GURL& url,
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
175   // for commit.
176   std::string script = base::StringPrintf(
177       "setTimeout(\""
178       "var iframes = document.getElementById('%s');iframes.src='%s';"
179       "\",0)",
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();
187   return result;
188 }
189
190 void SitePerProcessBrowserTest::SetUpCommandLine(CommandLine* command_line) {
191   command_line->AppendSwitch(switches::kSitePerProcess);
192 };
193
194 void SitePerProcessBrowserTest::SetUpOnMainThread() {
195   host_resolver()->AddRule("*", "127.0.0.1");
196   ASSERT_TRUE(embedded_test_server()->InitializeAndWaitUntilReady());
197   SetupCrossSiteRedirector(embedded_test_server());
198 }
199
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);
205
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();
210
211   SitePerProcessWebContentsObserver observer(shell()->web_contents());
212
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());
219   {
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());
226   }
227   RenderFrameProxyHost* proxy_to_parent =
228       child->render_manager()->GetRenderFrameProxyHost(
229           shell()->web_contents()->GetSiteInstance());
230   EXPECT_FALSE(proxy_to_parent);
231
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());
238
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);
247   {
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());
254   }
255   proxy_to_parent = child->render_manager()->GetProxyToParent();
256   EXPECT_TRUE(proxy_to_parent);
257   EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
258   EXPECT_EQ(
259       rvh->GetView(),
260       proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
261
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());
267
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());
282   {
283     std::set<RenderWidgetHostView*> views_set =
284         static_cast<WebContentsImpl*>(shell()->web_contents())
285             ->GetRenderWidgetHostViewsInTree();
286     EXPECT_EQ(2U, views_set.size());
287   }
288   EXPECT_EQ(proxy_to_parent, child->render_manager()->GetProxyToParent());
289   EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
290   EXPECT_EQ(
291       child->current_frame_host()->render_view_host()->GetView(),
292       proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
293 }
294
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);
298
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();
303
304   SitePerProcessWebContentsObserver observer(shell()->web_contents());
305
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());
312
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());
318
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);
323
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());
330
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());
339
340   // Navigate back to the parent's origin and ensure we return to the
341   // parent's process.
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());
347 }
348
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);
356
357   StartFrameAtDataURL();
358
359   // These must stay in scope with replace_host.
360   GURL::Replacements replace_host;
361   std::string foo_com("foo.com");
362
363   // Load cross-site page into iframe.
364   EXPECT_TRUE(NavigateIframeToURL(
365       shell(),
366       embedded_test_server()->GetURL("/cross-site/foo.com/title2.html"),
367       "test"));
368
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());
378
379   EXPECT_TRUE(
380       child->current_frame_host()->render_view_host()->IsRenderViewLive());
381   EXPECT_TRUE(child->current_frame_host()->IsRenderFrameLive());
382
383   // Crash the subframe process.
384   RenderProcessHost* root_process = root->current_frame_host()->GetProcess();
385   RenderProcessHost* child_process = child->current_frame_host()->GetProcess();
386   {
387     RenderProcessHostWatcher crash_observer(
388         child_process,
389         RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
390     base::KillProcess(child_process->GetHandle(), 0, false);
391     crash_observer.Wait();
392   }
393
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());
398
399   EXPECT_FALSE(
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_);
403
404   // Now crash the top-level page to clear the child frame.
405   {
406     RenderProcessHostWatcher crash_observer(
407         root_process,
408         RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
409     base::KillProcess(root_process->GetHandle(), 0, false);
410     crash_observer.Wait();
411   }
412   EXPECT_EQ(0U, root->child_count());
413   EXPECT_EQ(GURL(), root->current_url());
414 }
415
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());
428
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"));
432
433   NavigateToURL(shell(), main_url);
434
435   SitePerProcessWebContentsObserver observer(shell()->web_contents());
436   {
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());
446   }
447
448   {
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());
457   }
458
459   {
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());
469   }
470
471   {
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"));
478
479     EXPECT_EQ(observer.navigation_url(), https_url);
480     EXPECT_FALSE(observer.navigation_succeeded());
481    }
482
483   {
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()));
488
489     RedirectNotificationObserver load_observer2(
490         NOTIFICATION_LOAD_STOP,
491         Source<NavigationController>(
492             &shell()->web_contents()->GetController()));
493
494     EXPECT_TRUE(NavigateIframeToURL(shell(),
495                                     client_redirect_http_url, "test"));
496
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());
500
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());
505   }
506
507   {
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());
516    }
517
518   {
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()));
527
528     EXPECT_TRUE(NavigateIframeToURL(shell(),
529                                     client_redirect_http_url, "test"));
530
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());
534
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());
539   }
540 }
541
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());
554
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"));
558
559   NavigateToURL(shell(), main_url);
560
561   SitePerProcessWebContentsObserver observer(shell()->web_contents());
562   {
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()));
569
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()));
575
576     EXPECT_TRUE(NavigateIframeToURL(shell(), client_redirect_http_url, "test"));
577
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());
582   }
583
584   {
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());
595   }
596
597   {
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"));
605
606     // DidFailProvisionalLoad when navigating to https_url.
607     EXPECT_EQ(observer.navigation_url(), https_url);
608     EXPECT_FALSE(observer.navigation_succeeded());
609   }
610
611   {
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"));
619
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());
623   }
624 }
625
626 // Ensure that when navigating a frame cross-process RenderFrameProxyHosts are
627 // created in the FrameTree skipping the subtree of the navigating frame.
628 //
629 // Disabled on Mac due to flakiness on ASAN. http://crbug.com/425248
630 #if defined(OS_MACOSX)
631 #define MAYBE_ProxyCreationSkipsSubtree DISABLED_ProxyCreationSkipsSubtree
632 #else
633 #define MAYBE_ProxyCreationSkipsSubtree ProxyCreationSkipsSubtree
634 #endif
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);
639
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();
644
645   EXPECT_TRUE(root->child_at(1) != NULL);
646   EXPECT_EQ(2U, root->child_at(1)->child_count());
647
648   {
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);
659   }
660
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");
664
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;
672   {
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());
680
681     site = child->render_manager()->pending_frame_host()->GetSiteInstance();
682     EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site);
683
684     EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(site));
685     EXPECT_TRUE(
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) {
689       EXPECT_FALSE(
690           child->child_at(i)->render_manager()->GetRenderFrameProxyHost(site));
691     }
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());
698   }
699
700   // Load another cross-site page into the same iframe.
701   cross_site_url = embedded_test_server()->GetURL("bar.com", "/title2.html");
702   {
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);
716
717     SiteInstance* site2 =
718         child->render_manager()->pending_frame_host()->GetSiteInstance();
719     EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site2);
720     EXPECT_NE(site, site2);
721
722     EXPECT_TRUE(root->render_manager()->GetRenderFrameProxyHost(site2));
723     EXPECT_TRUE(
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) {
727       EXPECT_FALSE(
728           child->child_at(i)->render_manager()->GetRenderFrameProxyHost(site2));
729     }
730
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());
735   }
736 }
737
738 }  // namespace content