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 "base/command_line.h"
      6 #include "base/strings/stringprintf.h"
      7 #include "base/strings/utf_string_conversions.h"
      8 #include "content/browser/web_contents/web_contents_impl.h"
      9 #include "content/public/browser/notification_observer.h"
     10 #include "content/public/browser/notification_service.h"
     11 #include "content/public/browser/notification_types.h"
     12 #include "content/public/browser/web_contents_observer.h"
     13 #include "content/public/common/content_switches.h"
     14 #include "content/public/test/browser_test_utils.h"
     15 #include "content/public/test/test_utils.h"
     16 #include "content/shell/shell.h"
     17 #include "content/test/content_browser_test.h"
     18 #include "content/test/content_browser_test_utils.h"
     19 
     20 namespace content {
     21 
     22 class SitePerProcessWebContentsObserver: public WebContentsObserver {
     23  public:
     24   explicit SitePerProcessWebContentsObserver(WebContents* web_contents)
     25       : WebContentsObserver(web_contents),
     26         navigation_succeeded_(true) {}
     27   virtual ~SitePerProcessWebContentsObserver() {}
     28 
     29   virtual void DidFailProvisionalLoad(
     30       int64 frame_id,
     31       bool is_main_frame,
     32       const GURL& validated_url,
     33       int error_code,
     34       const string16& error_description,
     35       RenderViewHost* render_view_host) OVERRIDE {
     36     navigation_url_ = validated_url;
     37     navigation_succeeded_ = false;
     38   }
     39 
     40   virtual void DidCommitProvisionalLoadForFrame(
     41       int64 frame_id,
     42       bool is_main_frame,
     43       const GURL& url,
     44       PageTransition transition_type,
     45       RenderViewHost* render_view_host) OVERRIDE{
     46     navigation_url_ = url;
     47     navigation_succeeded_ = true;
     48   }
     49 
     50   const GURL& navigation_url() const {
     51     return navigation_url_;
     52   }
     53 
     54   int navigation_succeeded() const { return navigation_succeeded_; }
     55 
     56  private:
     57   GURL navigation_url_;
     58   bool navigation_succeeded_;
     59 
     60   DISALLOW_COPY_AND_ASSIGN(SitePerProcessWebContentsObserver);
     61 };
     62 
     63 class RedirectNotificationObserver : public NotificationObserver {
     64  public:
     65   // Register to listen for notifications of the given type from either a
     66   // specific source, or from all sources if |source| is
     67   // NotificationService::AllSources().
     68   RedirectNotificationObserver(int notification_type,
     69                                const NotificationSource& source);
     70   virtual ~RedirectNotificationObserver();
     71 
     72   // Wait until the specified notification occurs.  If the notification was
     73   // emitted between the construction of this object and this call then it
     74   // returns immediately.
     75   void Wait();
     76 
     77   // Returns NotificationService::AllSources() if we haven't observed a
     78   // notification yet.
     79   const NotificationSource& source() const {
     80     return source_;
     81   }
     82 
     83   const NotificationDetails& details() const {
     84     return details_;
     85   }
     86 
     87   // NotificationObserver:
     88   virtual void Observe(int type,
     89                        const NotificationSource& source,
     90                        const NotificationDetails& details) OVERRIDE;
     91 
     92  private:
     93   bool seen_;
     94   bool seen_twice_;
     95   bool running_;
     96   NotificationRegistrar registrar_;
     97 
     98   NotificationSource source_;
     99   NotificationDetails details_;
    100   scoped_refptr<MessageLoopRunner> message_loop_runner_;
    101 
    102   DISALLOW_COPY_AND_ASSIGN(RedirectNotificationObserver);
    103 };
    104 
    105 RedirectNotificationObserver::RedirectNotificationObserver(
    106     int notification_type,
    107     const NotificationSource& source)
    108     : seen_(false),
    109       running_(false),
    110       source_(NotificationService::AllSources()) {
    111   registrar_.Add(this, notification_type, source);
    112 }
    113 
    114 RedirectNotificationObserver::~RedirectNotificationObserver() {}
    115 
    116 void RedirectNotificationObserver::Wait() {
    117   if (seen_ && seen_twice_)
    118     return;
    119 
    120   running_ = true;
    121   message_loop_runner_ = new MessageLoopRunner;
    122   message_loop_runner_->Run();
    123   EXPECT_TRUE(seen_);
    124 }
    125 
    126 void RedirectNotificationObserver::Observe(
    127     int type,
    128     const NotificationSource& source,
    129     const NotificationDetails& details) {
    130   source_ = source;
    131   details_ = details;
    132   seen_twice_ = seen_;
    133   seen_ = true;
    134   if (!running_)
    135     return;
    136 
    137   message_loop_runner_->Quit();
    138   running_ = false;
    139 }
    140 
    141 class SitePerProcessBrowserTest : public ContentBrowserTest {
    142  public:
    143   SitePerProcessBrowserTest() {}
    144 
    145   bool NavigateIframeToURL(Shell* window,
    146                            const GURL& url,
    147                            std::string iframe_id) {
    148     std::string script = base::StringPrintf(
    149         "var iframes = document.getElementById('%s');iframes.src='%s';",
    150         iframe_id.c_str(), url.spec().c_str());
    151     WindowedNotificationObserver load_observer(
    152         NOTIFICATION_LOAD_STOP,
    153         Source<NavigationController>(
    154             &shell()->web_contents()->GetController()));
    155     bool result = ExecuteScript(window->web_contents(), script);
    156     load_observer.Wait();
    157     return result;
    158   }
    159 
    160   virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
    161     command_line->AppendSwitch(switches::kSitePerProcess);
    162   }
    163 };
    164 
    165 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
    166 // security checks are back in place.
    167 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest, DISABLED_CrossSiteIframe) {
    168   ASSERT_TRUE(test_server()->Start());
    169   net::SpawnedTestServer https_server(
    170       net::SpawnedTestServer::TYPE_HTTPS,
    171       net::SpawnedTestServer::kLocalhost,
    172       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
    173   ASSERT_TRUE(https_server.Start());
    174   GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
    175 
    176   NavigateToURL(shell(), main_url);
    177 
    178   SitePerProcessWebContentsObserver observer(shell()->web_contents());
    179   {
    180     // Load same-site page into Iframe.
    181     GURL http_url(test_server()->GetURL("files/title1.html"));
    182     EXPECT_TRUE(NavigateIframeToURL(shell(), http_url, "test"));
    183     EXPECT_EQ(observer.navigation_url(), http_url);
    184     EXPECT_TRUE(observer.navigation_succeeded());
    185   }
    186 
    187   {
    188     // Load cross-site page into Iframe.
    189     GURL https_url(https_server.GetURL("files/title1.html"));
    190     EXPECT_TRUE(NavigateIframeToURL(shell(), https_url, "test"));
    191     EXPECT_EQ(observer.navigation_url(), https_url);
    192     EXPECT_FALSE(observer.navigation_succeeded());
    193   }
    194 }
    195 
    196 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
    197 // security checks are back in place.
    198 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
    199                        DISABLED_CrossSiteIframeRedirectOnce) {
    200   ASSERT_TRUE(test_server()->Start());
    201   net::SpawnedTestServer https_server(
    202       net::SpawnedTestServer::TYPE_HTTPS,
    203       net::SpawnedTestServer::kLocalhost,
    204       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
    205   ASSERT_TRUE(https_server.Start());
    206 
    207   GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
    208   GURL http_url(test_server()->GetURL("files/title1.html"));
    209   GURL https_url(https_server.GetURL("files/title1.html"));
    210 
    211   NavigateToURL(shell(), main_url);
    212 
    213   SitePerProcessWebContentsObserver observer(shell()->web_contents());
    214   {
    215     // Load cross-site client-redirect page into Iframe.
    216     // Should be blocked.
    217     GURL client_redirect_https_url(https_server.GetURL(
    218         "client-redirect?files/title1.html"));
    219     EXPECT_TRUE(NavigateIframeToURL(shell(),
    220                                     client_redirect_https_url, "test"));
    221     // DidFailProvisionalLoad when navigating to client_redirect_https_url.
    222     EXPECT_EQ(observer.navigation_url(), client_redirect_https_url);
    223     EXPECT_FALSE(observer.navigation_succeeded());
    224   }
    225 
    226   {
    227     // Load cross-site server-redirect page into Iframe,
    228     // which redirects to same-site page.
    229     GURL server_redirect_http_url(https_server.GetURL(
    230         "server-redirect?" + http_url.spec()));
    231     EXPECT_TRUE(NavigateIframeToURL(shell(),
    232                                     server_redirect_http_url, "test"));
    233     EXPECT_EQ(observer.navigation_url(), http_url);
    234     EXPECT_TRUE(observer.navigation_succeeded());
    235   }
    236 
    237   {
    238     // Load cross-site server-redirect page into Iframe,
    239     // which redirects to cross-site page.
    240     GURL server_redirect_http_url(https_server.GetURL(
    241         "server-redirect?files/title1.html"));
    242     EXPECT_TRUE(NavigateIframeToURL(shell(),
    243                                     server_redirect_http_url, "test"));
    244     // DidFailProvisionalLoad when navigating to https_url.
    245     EXPECT_EQ(observer.navigation_url(), https_url);
    246     EXPECT_FALSE(observer.navigation_succeeded());
    247   }
    248 
    249   {
    250     // Load same-site server-redirect page into Iframe,
    251     // which redirects to cross-site page.
    252     GURL server_redirect_http_url(test_server()->GetURL(
    253         "server-redirect?" + https_url.spec()));
    254     EXPECT_TRUE(NavigateIframeToURL(shell(),
    255                                     server_redirect_http_url, "test"));
    256 
    257     EXPECT_EQ(observer.navigation_url(), https_url);
    258     EXPECT_FALSE(observer.navigation_succeeded());
    259    }
    260 
    261   {
    262     // Load same-site client-redirect page into Iframe,
    263     // which redirects to cross-site page.
    264     GURL client_redirect_http_url(test_server()->GetURL(
    265         "client-redirect?" + https_url.spec()));
    266 
    267     RedirectNotificationObserver load_observer2(
    268         NOTIFICATION_LOAD_STOP,
    269         Source<NavigationController>(
    270             &shell()->web_contents()->GetController()));
    271 
    272     EXPECT_TRUE(NavigateIframeToURL(shell(),
    273                                     client_redirect_http_url, "test"));
    274 
    275     // Same-site Client-Redirect Page should be loaded successfully.
    276     EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
    277     EXPECT_TRUE(observer.navigation_succeeded());
    278 
    279     // Redirecting to Cross-site Page should be blocked.
    280     load_observer2.Wait();
    281     EXPECT_EQ(observer.navigation_url(), https_url);
    282     EXPECT_FALSE(observer.navigation_succeeded());
    283   }
    284 
    285   {
    286     // Load same-site server-redirect page into Iframe,
    287     // which redirects to same-site page.
    288     GURL server_redirect_http_url(test_server()->GetURL(
    289         "server-redirect?files/title1.html"));
    290     EXPECT_TRUE(NavigateIframeToURL(shell(),
    291                                     server_redirect_http_url, "test"));
    292     EXPECT_EQ(observer.navigation_url(), http_url);
    293     EXPECT_TRUE(observer.navigation_succeeded());
    294    }
    295 
    296   {
    297     // Load same-site client-redirect page into Iframe,
    298     // which redirects to same-site page.
    299     GURL client_redirect_http_url(test_server()->GetURL(
    300         "client-redirect?" + http_url.spec()));
    301     RedirectNotificationObserver load_observer2(
    302         NOTIFICATION_LOAD_STOP,
    303         Source<NavigationController>(
    304             &shell()->web_contents()->GetController()));
    305 
    306     EXPECT_TRUE(NavigateIframeToURL(shell(),
    307                                     client_redirect_http_url, "test"));
    308 
    309     // Same-site Client-Redirect Page should be loaded successfully.
    310     EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
    311     EXPECT_TRUE(observer.navigation_succeeded());
    312 
    313     // Redirecting to Same-site Page should be loaded successfully.
    314     load_observer2.Wait();
    315     EXPECT_EQ(observer.navigation_url(), http_url);
    316     EXPECT_TRUE(observer.navigation_succeeded());
    317   }
    318 }
    319 
    320 // TODO(nasko): Disable this test until out-of-process iframes is ready and the
    321 // security checks are back in place.
    322 IN_PROC_BROWSER_TEST_F(SitePerProcessBrowserTest,
    323                        DISABLED_CrossSiteIframeRedirectTwice) {
    324   ASSERT_TRUE(test_server()->Start());
    325   net::SpawnedTestServer https_server(
    326       net::SpawnedTestServer::TYPE_HTTPS,
    327       net::SpawnedTestServer::kLocalhost,
    328       base::FilePath(FILE_PATH_LITERAL("content/test/data")));
    329   ASSERT_TRUE(https_server.Start());
    330 
    331   GURL main_url(test_server()->GetURL("files/site_per_process_main.html"));
    332   GURL http_url(test_server()->GetURL("files/title1.html"));
    333   GURL https_url(https_server.GetURL("files/title1.html"));
    334 
    335   NavigateToURL(shell(), main_url);
    336 
    337   SitePerProcessWebContentsObserver observer(shell()->web_contents());
    338   {
    339     // Load client-redirect page pointing to a cross-site client-redirect page,
    340     // which eventually redirects back to same-site page.
    341     GURL client_redirect_https_url(https_server.GetURL(
    342         "client-redirect?" + http_url.spec()));
    343     GURL client_redirect_http_url(test_server()->GetURL(
    344         "client-redirect?" + client_redirect_https_url.spec()));
    345 
    346     // We should wait until second client redirect get cancelled.
    347     RedirectNotificationObserver load_observer2(
    348         NOTIFICATION_LOAD_STOP,
    349         Source<NavigationController>(
    350             &shell()->web_contents()->GetController()));
    351 
    352     EXPECT_TRUE(NavigateIframeToURL(shell(), client_redirect_http_url, "test"));
    353 
    354     // DidFailProvisionalLoad when navigating to client_redirect_https_url.
    355     load_observer2.Wait();
    356     EXPECT_EQ(observer.navigation_url(), client_redirect_https_url);
    357     EXPECT_FALSE(observer.navigation_succeeded());
    358   }
    359 
    360   {
    361     // Load server-redirect page pointing to a cross-site server-redirect page,
    362     // which eventually redirect back to same-site page.
    363     GURL server_redirect_https_url(https_server.GetURL(
    364         "server-redirect?" + http_url.spec()));
    365     GURL server_redirect_http_url(test_server()->GetURL(
    366         "server-redirect?" + server_redirect_https_url.spec()));
    367     EXPECT_TRUE(NavigateIframeToURL(shell(),
    368                                     server_redirect_http_url, "test"));
    369     EXPECT_EQ(observer.navigation_url(), http_url);
    370     EXPECT_TRUE(observer.navigation_succeeded());
    371   }
    372 
    373   {
    374     // Load server-redirect page pointing to a cross-site server-redirect page,
    375     // which eventually redirects back to cross-site page.
    376     GURL server_redirect_https_url(https_server.GetURL(
    377         "server-redirect?" + https_url.spec()));
    378     GURL server_redirect_http_url(test_server()->GetURL(
    379         "server-redirect?" + server_redirect_https_url.spec()));
    380     EXPECT_TRUE(NavigateIframeToURL(shell(), server_redirect_http_url, "test"));
    381 
    382     // DidFailProvisionalLoad when navigating to https_url.
    383     EXPECT_EQ(observer.navigation_url(), https_url);
    384     EXPECT_FALSE(observer.navigation_succeeded());
    385   }
    386 
    387   {
    388     // Load server-redirect page pointing to a cross-site client-redirect page,
    389     // which eventually redirects back to same-site page.
    390     GURL client_redirect_http_url(https_server.GetURL(
    391         "client-redirect?" + http_url.spec()));
    392     GURL server_redirect_http_url(test_server()->GetURL(
    393         "server-redirect?" + client_redirect_http_url.spec()));
    394     EXPECT_TRUE(NavigateIframeToURL(shell(), server_redirect_http_url, "test"));
    395 
    396     // DidFailProvisionalLoad when navigating to client_redirect_http_url.
    397     EXPECT_EQ(observer.navigation_url(), client_redirect_http_url);
    398     EXPECT_FALSE(observer.navigation_succeeded());
    399   }
    400 }
    401 
    402 }
    403