Home | History | Annotate | Download | only in browser
      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/render_frame_proxy_host.h"
     12 #include "content/browser/frame_host/render_widget_host_view_child_frame.h"
     13 #include "content/browser/renderer_host/render_view_host_impl.h"
     14 #include "content/browser/web_contents/web_contents_impl.h"
     15 #include "content/public/browser/notification_observer.h"
     16 #include "content/public/browser/notification_service.h"
     17 #include "content/public/browser/notification_types.h"
     18 #include "content/public/browser/web_contents_observer.h"
     19 #include "content/public/common/content_switches.h"
     20 #include "content/public/test/browser_test_utils.h"
     21 #include "content/public/test/content_browser_test_utils.h"
     22 #include "content/public/test/test_utils.h"
     23 #include "content/shell/browser/shell.h"
     24 #include "content/test/content_browser_test_utils_internal.h"
     25 #include "net/dns/mock_host_resolver.h"
     26 
     27 namespace content {
     28 
     29 class SitePerProcessWebContentsObserver: public WebContentsObserver {
     30  public:
     31   explicit SitePerProcessWebContentsObserver(WebContents* web_contents)
     32       : WebContentsObserver(web_contents),
     33         navigation_succeeded_(false) {}
     34   virtual ~SitePerProcessWebContentsObserver() {}
     35 
     36   virtual void DidStartProvisionalLoadForFrame(
     37       RenderFrameHost* render_frame_host,
     38       const GURL& validated_url,
     39       bool is_error_page,
     40       bool is_iframe_srcdoc) OVERRIDE {
     41     navigation_succeeded_ = false;
     42   }
     43 
     44   virtual void DidFailProvisionalLoad(
     45       RenderFrameHost* render_frame_host,
     46       const GURL& validated_url,
     47       int error_code,
     48       const base::string16& error_description) OVERRIDE {
     49     navigation_url_ = validated_url;
     50     navigation_succeeded_ = false;
     51   }
     52 
     53   virtual void DidCommitProvisionalLoadForFrame(
     54       RenderFrameHost* render_frame_host,
     55       const GURL& url,
     56       ui::PageTransition transition_type) OVERRIDE {
     57     navigation_url_ = url;
     58     navigation_succeeded_ = true;
     59   }
     60 
     61   const GURL& navigation_url() const {
     62     return navigation_url_;
     63   }
     64 
     65   int navigation_succeeded() const { return navigation_succeeded_; }
     66 
     67  private:
     68   GURL navigation_url_;
     69   bool navigation_succeeded_;
     70 
     71   DISALLOW_COPY_AND_ASSIGN(SitePerProcessWebContentsObserver);
     72 };
     73 
     74 class RedirectNotificationObserver : public NotificationObserver {
     75  public:
     76   // Register to listen for notifications of the given type from either a
     77   // specific source, or from all sources if |source| is
     78   // NotificationService::AllSources().
     79   RedirectNotificationObserver(int notification_type,
     80                                const NotificationSource& source);
     81   virtual ~RedirectNotificationObserver();
     82 
     83   // Wait until the specified notification occurs.  If the notification was
     84   // emitted between the construction of this object and this call then it
     85   // returns immediately.
     86   void Wait();
     87 
     88   // Returns NotificationService::AllSources() if we haven't observed a
     89   // notification yet.
     90   const NotificationSource& source() const {
     91     return source_;
     92   }
     93 
     94   const NotificationDetails& details() const {
     95     return details_;
     96   }
     97 
     98   // NotificationObserver:
     99   virtual void Observe(int type,
    100                        const NotificationSource& source,
    101                        const NotificationDetails& details) OVERRIDE;
    102 
    103  private:
    104   bool seen_;
    105   bool seen_twice_;
    106   bool running_;
    107   NotificationRegistrar registrar_;
    108 
    109   NotificationSource source_;
    110   NotificationDetails details_;
    111   scoped_refptr<MessageLoopRunner> message_loop_runner_;
    112 
    113   DISALLOW_COPY_AND_ASSIGN(RedirectNotificationObserver);
    114 };
    115 
    116 RedirectNotificationObserver::RedirectNotificationObserver(
    117     int notification_type,
    118     const NotificationSource& source)
    119     : seen_(false),
    120       running_(false),
    121       source_(NotificationService::AllSources()) {
    122   registrar_.Add(this, notification_type, source);
    123 }
    124 
    125 RedirectNotificationObserver::~RedirectNotificationObserver() {}
    126 
    127 void RedirectNotificationObserver::Wait() {
    128   if (seen_ && seen_twice_)
    129     return;
    130 
    131   running_ = true;
    132   message_loop_runner_ = new MessageLoopRunner;
    133   message_loop_runner_->Run();
    134   EXPECT_TRUE(seen_);
    135 }
    136 
    137 void RedirectNotificationObserver::Observe(
    138     int type,
    139     const NotificationSource& source,
    140     const NotificationDetails& details) {
    141   source_ = source;
    142   details_ = details;
    143   seen_twice_ = seen_;
    144   seen_ = true;
    145   if (!running_)
    146     return;
    147 
    148   message_loop_runner_->Quit();
    149   running_ = false;
    150 }
    151 
    152 //
    153 // SitePerProcessBrowserTest
    154 //
    155 
    156 SitePerProcessBrowserTest::SitePerProcessBrowserTest() {
    157 };
    158 
    159 void SitePerProcessBrowserTest::StartFrameAtDataURL() {
    160   std::string data_url_script =
    161       "var iframes = document.getElementById('test');iframes.src="
    162       "'data:text/html,dataurl';";
    163   ASSERT_TRUE(ExecuteScript(shell()->web_contents(), data_url_script));
    164 }
    165 
    166 bool SitePerProcessBrowserTest::NavigateIframeToURL(Shell* window,
    167                                                     const GURL& url,
    168                                                     std::string iframe_id) {
    169   // TODO(creis): This should wait for LOAD_STOP, but cross-site subframe
    170   // navigations generate extra DidStartLoading and DidStopLoading messages.
    171   // Until we replace swappedout:// with frame proxies, we need to listen for
    172   // something else.  For now, we trigger NEW_SUBFRAME navigations and listen
    173   // for commit.
    174   std::string script = base::StringPrintf(
    175       "setTimeout(\""
    176       "var iframes = document.getElementById('%s');iframes.src='%s';"
    177       "\",0)",
    178       iframe_id.c_str(), url.spec().c_str());
    179   WindowedNotificationObserver load_observer(
    180       NOTIFICATION_NAV_ENTRY_COMMITTED,
    181       Source<NavigationController>(
    182           &window->web_contents()->GetController()));
    183   bool result = ExecuteScript(window->web_contents(), script);
    184   load_observer.Wait();
    185   return result;
    186 }
    187 
    188 void SitePerProcessBrowserTest::SetUpCommandLine(CommandLine* command_line) {
    189   command_line->AppendSwitch(switches::kSitePerProcess);
    190 };
    191 
    192 // It fails on ChromeOS and Android, so disabled while investigating.
    193 // http://crbug.com/399775
    194 #if defined(OS_ANDROID) || defined(OS_CHROMEOS)
    195 #define MAYBE_CrossSiteIframe DISABLED_CrossSiteIframe
    196 #else
    197 #define MAYBE_CrossSiteIframe CrossSiteIframe
    198 #endif
    199 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, MAYBE_CrossSiteIframe) {
    200   host_resolver()->AddRule("*", "127.0.0.1");
    201   ASSERT_TRUE(test_server()->Start());
    202   GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
    203   NavigateToURL(shell(), main_url);
    204 
    205   // It is safe to obtain the root frame tree node here, as it doesn't change.
    206   FrameTreeNode* root =
    207       static_cast<WebContentsImpl*>(shell()->web_contents())->
    208           GetFrameTree()->root();
    209 
    210   SitePerProcessWebContentsObserver observer(shell()->web_contents());
    211 
    212   // Load same-site page into iframe.
    213   FrameTreeNode* child = root->child_at(0);
    214   GURL http_url(test_server()->GetURL("files/title1.html"));
    215   NavigateFrameToURL(child, http_url);
    216   EXPECT_EQ(http_url, observer.navigation_url());
    217   EXPECT_TRUE(observer.navigation_succeeded());
    218   {
    219     // There should be only one RenderWidgetHost when there are no
    220     // cross-process iframes.
    221     std::set<RenderWidgetHostView*> views_set =
    222         static_cast<WebContentsImpl*>(shell()->web_contents())
    223             ->GetRenderWidgetHostViewsInTree();
    224     EXPECT_EQ(1U, views_set.size());
    225   }
    226   RenderFrameProxyHost* proxy_to_parent =
    227       child->render_manager()->GetRenderFrameProxyHost(
    228           shell()->web_contents()->GetSiteInstance());
    229   EXPECT_FALSE(proxy_to_parent);
    230 
    231   // These must stay in scope with replace_host.
    232   GURL::Replacements replace_host;
    233   std::string foo_com("foo.com");
    234 
    235   // Load cross-site page into iframe.
    236   GURL cross_site_url(test_server()->GetURL("files/title2.html"));
    237   replace_host.SetHostStr(foo_com);
    238   cross_site_url = cross_site_url.ReplaceComponents(replace_host);
    239   NavigateFrameToURL(root->child_at(0), cross_site_url);
    240   EXPECT_EQ(cross_site_url, observer.navigation_url());
    241   EXPECT_TRUE(observer.navigation_succeeded());
    242 
    243   // Ensure that we have created a new process for the subframe.
    244   ASSERT_EQ(1U, root->child_count());
    245   SiteInstance* site_instance = child->current_frame_host()->GetSiteInstance();
    246   RenderViewHost* rvh = child->current_frame_host()->render_view_host();
    247   RenderProcessHost* rph = child->current_frame_host()->GetProcess();
    248   EXPECT_NE(shell()->web_contents()->GetRenderViewHost(), rvh);
    249   EXPECT_NE(shell()->web_contents()->GetSiteInstance(), site_instance);
    250   EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(), rph);
    251   {
    252     // There should be now two RenderWidgetHosts, one for each process
    253     // rendering a frame.
    254     std::set<RenderWidgetHostView*> views_set =
    255         static_cast<WebContentsImpl*>(shell()->web_contents())
    256             ->GetRenderWidgetHostViewsInTree();
    257     EXPECT_EQ(2U, views_set.size());
    258   }
    259   proxy_to_parent = child->render_manager()->GetProxyToParent();
    260   EXPECT_TRUE(proxy_to_parent);
    261   EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
    262   EXPECT_EQ(
    263       rvh->GetView(),
    264       proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
    265 
    266   // Load another cross-site page into the same iframe.
    267   cross_site_url = test_server()->GetURL("files/title3.html");
    268   std::string bar_com("bar.com");
    269   replace_host.SetHostStr(bar_com);
    270   cross_site_url = cross_site_url.ReplaceComponents(replace_host);
    271   NavigateFrameToURL(root->child_at(0), cross_site_url);
    272   EXPECT_EQ(cross_site_url, observer.navigation_url());
    273   EXPECT_TRUE(observer.navigation_succeeded());
    274 
    275   // Check again that a new process is created and is different from the
    276   // top level one and the previous one.
    277   ASSERT_EQ(1U, root->child_count());
    278   child = root->child_at(0);
    279   EXPECT_NE(shell()->web_contents()->GetRenderViewHost(),
    280             child->current_frame_host()->render_view_host());
    281   EXPECT_NE(rvh, child->current_frame_host()->render_view_host());
    282   EXPECT_NE(shell()->web_contents()->GetSiteInstance(),
    283             child->current_frame_host()->GetSiteInstance());
    284   EXPECT_NE(site_instance,
    285             child->current_frame_host()->GetSiteInstance());
    286   EXPECT_NE(shell()->web_contents()->GetRenderProcessHost(),
    287             child->current_frame_host()->GetProcess());
    288   EXPECT_NE(rph, child->current_frame_host()->GetProcess());
    289   {
    290     std::set<RenderWidgetHostView*> views_set =
    291         static_cast<WebContentsImpl*>(shell()->web_contents())
    292             ->GetRenderWidgetHostViewsInTree();
    293     EXPECT_EQ(2U, views_set.size());
    294   }
    295   EXPECT_EQ(proxy_to_parent, child->render_manager()->GetProxyToParent());
    296   EXPECT_TRUE(proxy_to_parent->cross_process_frame_connector());
    297   EXPECT_EQ(
    298       child->current_frame_host()->render_view_host()->GetView(),
    299       proxy_to_parent->cross_process_frame_connector()->get_view_for_testing());
    300 }
    301 
    302 // Crash a subframe and ensures its children are cleared from the FrameTree.
    303 // See http://crbug.com/338508.
    304 // TODO(creis): Disabled for flakiness; see http://crbug.com/405582.
    305 // TODO(creis): Enable this on Android when we can kill the process there.
    306 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DISABLED_CrashSubframe) {
    307   host_resolver()->AddRule("*", "127.0.0.1");
    308   ASSERT_TRUE(test_server()->Start());
    309   GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
    310   NavigateToURL(shell(), main_url);
    311 
    312   StartFrameAtDataURL();
    313 
    314   // These must stay in scope with replace_host.
    315   GURL::Replacements replace_host;
    316   std::string foo_com("foo.com");
    317 
    318   // Load cross-site page into iframe.
    319   GURL cross_site_url(test_server()->GetURL("files/title2.html"));
    320   replace_host.SetHostStr(foo_com);
    321   cross_site_url = cross_site_url.ReplaceComponents(replace_host);
    322   EXPECT_TRUE(NavigateIframeToURL(shell(), cross_site_url, "test"));
    323 
    324   // Check the subframe process.
    325   FrameTreeNode* root =
    326       static_cast<WebContentsImpl*>(shell()->web_contents())->
    327           GetFrameTree()->root();
    328   ASSERT_EQ(1U, root->child_count());
    329   FrameTreeNode* child = root->child_at(0);
    330   EXPECT_EQ(main_url, root->current_url());
    331   EXPECT_EQ(cross_site_url, child->current_url());
    332 
    333   EXPECT_TRUE(
    334       child->current_frame_host()->render_view_host()->IsRenderViewLive());
    335   EXPECT_TRUE(child->current_frame_host()->IsRenderFrameLive());
    336 
    337   // Crash the subframe process.
    338   RenderProcessHost* root_process = root->current_frame_host()->GetProcess();
    339   RenderProcessHost* child_process = child->current_frame_host()->GetProcess();
    340   {
    341     RenderProcessHostWatcher crash_observer(
    342         child_process,
    343         RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
    344     base::KillProcess(child_process->GetHandle(), 0, false);
    345     crash_observer.Wait();
    346   }
    347 
    348   // Ensure that the child frame still exists but has been cleared.
    349   EXPECT_EQ(1U, root->child_count());
    350   EXPECT_EQ(main_url, root->current_url());
    351   EXPECT_EQ(GURL(), child->current_url());
    352 
    353   EXPECT_FALSE(
    354       child->current_frame_host()->render_view_host()->IsRenderViewLive());
    355   EXPECT_FALSE(child->current_frame_host()->IsRenderFrameLive());
    356   EXPECT_FALSE(child->current_frame_host()->render_frame_created_);
    357 
    358   // Now crash the top-level page to clear the child frame.
    359   {
    360     RenderProcessHostWatcher crash_observer(
    361         root_process,
    362         RenderProcessHostWatcher::WATCH_FOR_PROCESS_EXIT);
    363     base::KillProcess(root_process->GetHandle(), 0, false);
    364     crash_observer.Wait();
    365   }
    366   EXPECT_EQ(0U, root->child_count());
    367   EXPECT_EQ(GURL(), root->current_url());
    368 }
    369 
    370 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
    371 // security checks are back in place.
    372 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
    373 // on Android (http://crbug.com/187570).
    374 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
    375                        DISABLED_CrossSiteIframeRedirectOnce) {
    376   ASSERT_TRUE(test_server()->Start());
    377   net::SpawnedTestServer https_server(
    378       net::SpawnedTestServer::TYPE_HTTPS,
    379       net::SpawnedTestServer::kLocalhost,
    380       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
    381   ASSERT_TRUE(https_server.Start());
    382 
    383   GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
    384   GURL http_url(test_server()->GetURL("files/title1.html"));
    385   GURL https_url(https_server.GetURL("files/title1.html"));
    386 
    387   NavigateToURL(shell(), main_url);
    388 
    389   SitePerProcessWebContentsObserver observer(shell()->web_contents());
    390   {
    391     // Load cross-site client-redirect page into Iframe.
    392     // Should be blocked.
    393     GURL client_redirect_https_url(https_server.GetURL(
    394         "client-redirect?files/title1.html"));
    395     EXPECT_TRUE(NavigateIframeToURL(shell(),
    396                                     client_redirect_https_url, "test"));
    397     // DidFailProvisionalLoad when navigating to client_redirect_https_url.
    398     EXPECT_EQ(observer.navigation_url(), client_redirect_https_url);
    399     EXPECT_FALSE(observer.navigation_succeeded());
    400   }
    401 
    402   {
    403     // Load cross-site server-redirect page into Iframe,
    404     // which redirects to same-site page.
    405     GURL server_redirect_http_url(https_server.GetURL(
    406         "server-redirect?" + http_url.spec()));
    407     EXPECT_TRUE(NavigateIframeToURL(shell(),
    408                                     server_redirect_http_url, "test"));
    409     EXPECT_EQ(observer.navigation_url(), http_url);
    410     EXPECT_TRUE(observer.navigation_succeeded());
    411   }
    412 
    413   {
    414     // Load cross-site server-redirect page into Iframe,
    415     // which redirects to cross-site page.
    416     GURL server_redirect_http_url(https_server.GetURL(
    417         "server-redirect?files/title1.html"));
    418     EXPECT_TRUE(NavigateIframeToURL(shell(),
    419                                     server_redirect_http_url, "test"));
    420     // DidFailProvisionalLoad when navigating to https_url.
    421     EXPECT_EQ(observer.navigation_url(), https_url);
    422     EXPECT_FALSE(observer.navigation_succeeded());
    423   }
    424 
    425   {
    426     // Load same-site server-redirect page into Iframe,
    427     // which redirects to cross-site page.
    428     GURL server_redirect_http_url(test_server()->GetURL(
    429         "server-redirect?" + https_url.spec()));
    430     EXPECT_TRUE(NavigateIframeToURL(shell(),
    431                                     server_redirect_http_url, "test"));
    432 
    433     EXPECT_EQ(observer.navigation_url(), https_url);
    434     EXPECT_FALSE(observer.navigation_succeeded());
    435    }
    436 
    437   {
    438     // Load same-site client-redirect page into Iframe,
    439     // which redirects to cross-site page.
    440     GURL client_redirect_http_url(test_server()->GetURL(
    441         "client-redirect?" + https_url.spec()));
    442 
    443     RedirectNotificationObserver load_observer2(
    444         NOTIFICATION_LOAD_STOP,
    445         Source<NavigationController>(
    446             &shell()->web_contents()->GetController()));
    447 
    448     EXPECT_TRUE(NavigateIframeToURL(shell(),
    449                                     client_redirect_http_url, "test"));
    450 
    451     // Same-site Client-Redirect Page should be loaded successfully.
    452     EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
    453     EXPECT_TRUE(observer.navigation_succeeded());
    454 
    455     // Redirecting to Cross-site Page should be blocked.
    456     load_observer2.Wait();
    457     EXPECT_EQ(observer.navigation_url(), https_url);
    458     EXPECT_FALSE(observer.navigation_succeeded());
    459   }
    460 
    461   {
    462     // Load same-site server-redirect page into Iframe,
    463     // which redirects to same-site page.
    464     GURL server_redirect_http_url(test_server()->GetURL(
    465         "server-redirect?files/title1.html"));
    466     EXPECT_TRUE(NavigateIframeToURL(shell(),
    467                                     server_redirect_http_url, "test"));
    468     EXPECT_EQ(observer.navigation_url(), http_url);
    469     EXPECT_TRUE(observer.navigation_succeeded());
    470    }
    471 
    472   {
    473     // Load same-site client-redirect page into Iframe,
    474     // which redirects to same-site page.
    475     GURL client_redirect_http_url(test_server()->GetURL(
    476         "client-redirect?" + http_url.spec()));
    477     RedirectNotificationObserver load_observer2(
    478         NOTIFICATION_LOAD_STOP,
    479         Source<NavigationController>(
    480             &shell()->web_contents()->GetController()));
    481 
    482     EXPECT_TRUE(NavigateIframeToURL(shell(),
    483                                     client_redirect_http_url, "test"));
    484 
    485     // Same-site Client-Redirect Page should be loaded successfully.
    486     EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
    487     EXPECT_TRUE(observer.navigation_succeeded());
    488 
    489     // Redirecting to Same-site Page should be loaded successfully.
    490     load_observer2.Wait();
    491     EXPECT_EQ(observer.navigation_url(), http_url);
    492     EXPECT_TRUE(observer.navigation_succeeded());
    493   }
    494 }
    495 
    496 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
    497 // security checks are back in place.
    498 // TODO(creis): Replace SpawnedTestServer with host_resolver to get test to run
    499 // on Android (http://crbug.com/187570).
    500 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
    501                        DISABLED_CrossSiteIframeRedirectTwice) {
    502   ASSERT_TRUE(test_server()->Start());
    503   net::SpawnedTestServer https_server(
    504       net::SpawnedTestServer::TYPE_HTTPS,
    505       net::SpawnedTestServer::kLocalhost,
    506       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
    507   ASSERT_TRUE(https_server.Start());
    508 
    509   GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
    510   GURL http_url(test_server()->GetURL("files/title1.html"));
    511   GURL https_url(https_server.GetURL("files/title1.html"));
    512 
    513   NavigateToURL(shell(), main_url);
    514 
    515   SitePerProcessWebContentsObserver observer(shell()->web_contents());
    516   {
    517     // Load client-redirect page pointing to a cross-site client-redirect page,
    518     // which eventually redirects back to same-site page.
    519     GURL client_redirect_https_url(https_server.GetURL(
    520         "client-redirect?" + http_url.spec()));
    521     GURL client_redirect_http_url(test_server()->GetURL(
    522         "client-redirect?" + client_redirect_https_url.spec()));
    523 
    524     // We should wait until second client redirect get cancelled.
    525     RedirectNotificationObserver load_observer2(
    526         NOTIFICATION_LOAD_STOP,
    527         Source<NavigationController>(
    528             &shell()->web_contents()->GetController()));
    529 
    530     EXPECT_TRUE(NavigateIframeToURL(shell(), client_redirect_http_url, "test"));
    531 
    532     // DidFailProvisionalLoad when navigating to client_redirect_https_url.
    533     load_observer2.Wait();
    534     EXPECT_EQ(observer.navigation_url(), client_redirect_https_url);
    535     EXPECT_FALSE(observer.navigation_succeeded());
    536   }
    537 
    538   {
    539     // Load server-redirect page pointing to a cross-site server-redirect page,
    540     // which eventually redirect back to same-site page.
    541     GURL server_redirect_https_url(https_server.GetURL(
    542         "server-redirect?" + http_url.spec()));
    543     GURL server_redirect_http_url(test_server()->GetURL(
    544         "server-redirect?" + server_redirect_https_url.spec()));
    545     EXPECT_TRUE(NavigateIframeToURL(shell(),
    546                                     server_redirect_http_url, "test"));
    547     EXPECT_EQ(observer.navigation_url(), http_url);
    548     EXPECT_TRUE(observer.navigation_succeeded());
    549   }
    550 
    551   {
    552     // Load server-redirect page pointing to a cross-site server-redirect page,
    553     // which eventually redirects back to cross-site page.
    554     GURL server_redirect_https_url(https_server.GetURL(
    555         "server-redirect?" + https_url.spec()));
    556     GURL server_redirect_http_url(test_server()->GetURL(
    557         "server-redirect?" + server_redirect_https_url.spec()));
    558     EXPECT_TRUE(NavigateIframeToURL(shell(), server_redirect_http_url, "test"));
    559 
    560     // DidFailProvisionalLoad when navigating to https_url.
    561     EXPECT_EQ(observer.navigation_url(), https_url);
    562     EXPECT_FALSE(observer.navigation_succeeded());
    563   }
    564 
    565   {
    566     // Load server-redirect page pointing to a cross-site client-redirect page,
    567     // which eventually redirects back to same-site page.
    568     GURL client_redirect_http_url(https_server.GetURL(
    569         "client-redirect?" + http_url.spec()));
    570     GURL server_redirect_http_url(test_server()->GetURL(
    571         "server-redirect?" + client_redirect_http_url.spec()));
    572     EXPECT_TRUE(NavigateIframeToURL(shell(), server_redirect_http_url, "test"));
    573 
    574     // DidFailProvisionalLoad when navigating to client_redirect_http_url.
    575     EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
    576     EXPECT_FALSE(observer.navigation_succeeded());
    577   }
    578 }
    579 
    580 }  // namespace content
    581