Home | History | Annotate | Download | only in download
      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 "chrome/browser/download/download_request_limiter.h"
      6 
      7 #include "base/bind.h"
      8 #include "base/run_loop.h"
      9 #include "chrome/browser/content_settings/host_content_settings_map.h"
     10 #include "chrome/browser/download/download_request_infobar_delegate.h"
     11 #include "chrome/browser/infobars/infobar_service.h"
     12 #include "chrome/test/base/chrome_render_view_host_test_harness.h"
     13 #include "chrome/test/base/testing_profile.h"
     14 #include "content/public/browser/navigation_controller.h"
     15 #include "content/public/browser/web_contents.h"
     16 #include "testing/gtest/include/gtest/gtest.h"
     17 
     18 using content::WebContents;
     19 
     20 class DownloadRequestLimiterTest : public ChromeRenderViewHostTestHarness {
     21  public:
     22   enum TestingAction {
     23     ACCEPT,
     24     CANCEL,
     25     WAIT
     26   };
     27 
     28   virtual void SetUp() {
     29     ChromeRenderViewHostTestHarness::SetUp();
     30     InfoBarService::CreateForWebContents(web_contents());
     31     testing_action_ = ACCEPT;
     32     ask_allow_count_ = cancel_count_ = continue_count_ = 0;
     33     download_request_limiter_ = new DownloadRequestLimiter();
     34     fake_create_callback_ = base::Bind(
     35         &DownloadRequestLimiterTest::FakeCreate, base::Unretained(this));
     36     DownloadRequestInfoBarDelegate::SetCallbackForTesting(
     37         &fake_create_callback_);
     38     content_settings_ = new HostContentSettingsMap(profile_.GetPrefs(), false);
     39     DownloadRequestLimiter::SetContentSettingsForTesting(
     40         content_settings_.get());
     41   }
     42 
     43   void FakeCreate(
     44       InfoBarService* infobar_service,
     45       base::WeakPtr<DownloadRequestLimiter::TabDownloadState> host) {
     46     ask_allow_count_++;
     47     switch (testing_action_) {
     48       case ACCEPT:
     49         host->Accept();
     50         break;
     51       case CANCEL:
     52         host->Cancel();
     53         break;
     54       case WAIT:
     55         break;
     56     }
     57   }
     58 
     59   virtual void TearDown() {
     60     content_settings_->ShutdownOnUIThread();
     61     content_settings_ = NULL;
     62     UnsetDelegate();
     63     ChromeRenderViewHostTestHarness::TearDown();
     64   }
     65 
     66   virtual void UnsetDelegate() {
     67     DownloadRequestInfoBarDelegate::SetCallbackForTesting(NULL);
     68   }
     69 
     70   void CanDownload() {
     71     CanDownloadFor(web_contents());
     72   }
     73 
     74   void CanDownloadFor(WebContents* web_contents) {
     75     download_request_limiter_->CanDownloadImpl(
     76         web_contents,
     77         -1,  // request id
     78         "GET",  // request method
     79         base::Bind(&DownloadRequestLimiterTest::ContinueDownload,
     80                    base::Unretained(this)));
     81     base::RunLoop().RunUntilIdle();
     82   }
     83 
     84   void OnUserGesture() {
     85     OnUserGestureFor(web_contents());
     86   }
     87 
     88   void OnUserGestureFor(WebContents* web_contents) {
     89     DownloadRequestLimiter::TabDownloadState* state =
     90         download_request_limiter_->GetDownloadState(web_contents, NULL, false);
     91     if (state)
     92       state->DidGetUserGesture();
     93   }
     94 
     95   void AboutToNavigateRenderView() {
     96     DownloadRequestLimiter::TabDownloadState* state =
     97         download_request_limiter_->GetDownloadState(
     98             web_contents(), NULL, false);
     99     state->AboutToNavigateRenderView(NULL);
    100   }
    101 
    102   void ExpectAndResetCounts(
    103       int expect_continues,
    104       int expect_cancels,
    105       int expect_asks,
    106       int line) {
    107     EXPECT_EQ(expect_continues, continue_count_) << "line " << line;
    108     EXPECT_EQ(expect_cancels, cancel_count_) << "line " << line;
    109     EXPECT_EQ(expect_asks, ask_allow_count_) << "line " << line;
    110     continue_count_ = cancel_count_ = ask_allow_count_ = 0;
    111   }
    112 
    113  protected:
    114   void ContinueDownload(bool allow) {
    115     if (allow) {
    116       continue_count_++;
    117     } else {
    118       cancel_count_++;
    119     }
    120   }
    121 
    122   void SetHostContentSetting(WebContents* contents, ContentSetting setting) {
    123     content_settings_->SetContentSetting(
    124         ContentSettingsPattern::FromURL(contents->GetURL()),
    125         ContentSettingsPattern::Wildcard(),
    126         CONTENT_SETTINGS_TYPE_AUTOMATIC_DOWNLOADS,
    127         std::string(),
    128         setting);
    129   }
    130 
    131   scoped_refptr<DownloadRequestLimiter> download_request_limiter_;
    132 
    133   // The action that FakeCreate() should take.
    134   TestingAction testing_action_;
    135 
    136   // Number of times ContinueDownload was invoked.
    137   int continue_count_;
    138 
    139   // Number of times CancelDownload was invoked.
    140   int cancel_count_;
    141 
    142   // Number of times ShouldAllowDownload was invoked.
    143   int ask_allow_count_;
    144 
    145   scoped_refptr<HostContentSettingsMap> content_settings_;
    146 
    147  private:
    148   DownloadRequestInfoBarDelegate::FakeCreateCallback fake_create_callback_;
    149   TestingProfile profile_;
    150 };
    151 
    152 TEST_F(DownloadRequestLimiterTest,
    153        DownloadRequestLimiter_Allow) {
    154   // All tabs should initially start at ALLOW_ONE_DOWNLOAD.
    155   ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD,
    156             download_request_limiter_->GetDownloadStatus(web_contents()));
    157 
    158   // Ask if the tab can do a download. This moves to PROMPT_BEFORE_DOWNLOAD.
    159   CanDownload();
    160   ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD,
    161             download_request_limiter_->GetDownloadStatus(web_contents()));
    162   // We should have been told we can download.
    163   ExpectAndResetCounts(1, 0, 0, __LINE__);
    164 
    165   // Ask again. This triggers asking the delegate for allow/disallow.
    166   testing_action_ = ACCEPT;
    167   CanDownload();
    168   // This should ask us if the download is allowed.
    169   // We should have been told we can download.
    170   ExpectAndResetCounts(1, 0, 1, __LINE__);
    171   ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS,
    172             download_request_limiter_->GetDownloadStatus(web_contents()));
    173 
    174   // Ask again and make sure continue is invoked.
    175   CanDownload();
    176   // The state is at allow_all, which means the delegate shouldn't be asked.
    177   // We should have been told we can download.
    178   ExpectAndResetCounts(1, 0, 0, __LINE__);
    179   ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS,
    180             download_request_limiter_->GetDownloadStatus(web_contents()));
    181 }
    182 
    183 TEST_F(DownloadRequestLimiterTest,
    184        DownloadRequestLimiter_ResetOnNavigation) {
    185   NavigateAndCommit(GURL("http://foo.com/bar"));
    186 
    187   // Do two downloads, allowing the second so that we end up with allow all.
    188   CanDownload();
    189   ExpectAndResetCounts(1, 0, 0, __LINE__);
    190   ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD,
    191             download_request_limiter_->GetDownloadStatus(web_contents()));
    192 
    193   testing_action_ = ACCEPT;
    194   CanDownload();
    195   ExpectAndResetCounts(1, 0, 1, __LINE__);
    196   ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS,
    197             download_request_limiter_->GetDownloadStatus(web_contents()));
    198 
    199   // Navigate to a new URL with the same host, which shouldn't reset the allow
    200   // all state.
    201   NavigateAndCommit(GURL("http://foo.com/bar2"));
    202   CanDownload();
    203   ExpectAndResetCounts(1, 0, 0, __LINE__);
    204   ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS,
    205             download_request_limiter_->GetDownloadStatus(web_contents()));
    206 
    207   // Do a user gesture, because we're at allow all, this shouldn't change the
    208   // state.
    209   OnUserGesture();
    210   ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS,
    211             download_request_limiter_->GetDownloadStatus(web_contents()));
    212 
    213   // Navigate to a completely different host, which should reset the state.
    214   NavigateAndCommit(GURL("http://fooey.com"));
    215   ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD,
    216             download_request_limiter_->GetDownloadStatus(web_contents()));
    217 
    218   // Do two downloads, allowing the second so that we end up with allow all.
    219   CanDownload();
    220   ExpectAndResetCounts(1, 0, 0, __LINE__);
    221   ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD,
    222             download_request_limiter_->GetDownloadStatus(web_contents()));
    223 
    224   testing_action_ = CANCEL;
    225   CanDownload();
    226   ExpectAndResetCounts(0, 1, 1, __LINE__);
    227   ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED,
    228             download_request_limiter_->GetDownloadStatus(web_contents()));
    229 
    230   // Navigate to a new URL with the same host, which shouldn't reset the allow
    231   // all state.
    232   NavigateAndCommit(GURL("http://fooey.com/bar2"));
    233   CanDownload();
    234   ExpectAndResetCounts(0, 1, 0, __LINE__);
    235   ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED,
    236             download_request_limiter_->GetDownloadStatus(web_contents()));
    237 }
    238 
    239 TEST_F(DownloadRequestLimiterTest,
    240        DownloadRequestLimiter_ResetOnUserGesture) {
    241   NavigateAndCommit(GURL("http://foo.com/bar"));
    242 
    243   // Do one download, which should change to prompt before download.
    244   CanDownload();
    245   ExpectAndResetCounts(1, 0, 0, __LINE__);
    246   ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD,
    247             download_request_limiter_->GetDownloadStatus(web_contents()));
    248 
    249   // Do a user gesture, which should reset back to allow one.
    250   OnUserGesture();
    251   ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD,
    252             download_request_limiter_->GetDownloadStatus(web_contents()));
    253 
    254   // Ask twice, which triggers calling the delegate. Don't allow the download
    255   // so that we end up with not allowed.
    256   CanDownload();
    257   ExpectAndResetCounts(1, 0, 0, __LINE__);
    258   ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD,
    259             download_request_limiter_->GetDownloadStatus(web_contents()));
    260 
    261   testing_action_ = CANCEL;
    262   CanDownload();
    263   ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED,
    264             download_request_limiter_->GetDownloadStatus(web_contents()));
    265   ExpectAndResetCounts(0, 1, 1, __LINE__);
    266 
    267   // A user gesture now should NOT change the state.
    268   OnUserGesture();
    269   ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED,
    270             download_request_limiter_->GetDownloadStatus(web_contents()));
    271   // And make sure we really can't download.
    272   CanDownload();
    273   ExpectAndResetCounts(0, 1, 0, __LINE__);
    274   // And the state shouldn't have changed.
    275   ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED,
    276             download_request_limiter_->GetDownloadStatus(web_contents()));
    277 }
    278 
    279 TEST_F(DownloadRequestLimiterTest,
    280        DownloadRequestLimiter_ResetOnReload) {
    281   NavigateAndCommit(GURL("http://foo.com/bar"));
    282   ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD,
    283             download_request_limiter_->GetDownloadStatus(web_contents()));
    284 
    285   // If the user refreshes the page without responding to the infobar, pretend
    286   // like the refresh is the initial load: they get 1 free download (probably
    287   // the same as the actual initial load), then an infobar.
    288   testing_action_ = WAIT;
    289 
    290   CanDownload();
    291   ExpectAndResetCounts(1, 0, 0, __LINE__);
    292   ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD,
    293             download_request_limiter_->GetDownloadStatus(web_contents()));
    294 
    295   CanDownload();
    296   ExpectAndResetCounts(0, 0, 1, __LINE__);
    297   ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD,
    298             download_request_limiter_->GetDownloadStatus(web_contents()));
    299 
    300   AboutToNavigateRenderView();
    301   base::RunLoop().RunUntilIdle();
    302   ExpectAndResetCounts(0, 1, 0, __LINE__);
    303   ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD,
    304             download_request_limiter_->GetDownloadStatus(web_contents()));
    305 
    306   CanDownload();
    307   ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD,
    308             download_request_limiter_->GetDownloadStatus(web_contents()));
    309   ExpectAndResetCounts(1, 0, 0, __LINE__);
    310 
    311   testing_action_ = CANCEL;
    312   CanDownload();
    313   ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED,
    314             download_request_limiter_->GetDownloadStatus(web_contents()));
    315   ExpectAndResetCounts(0, 1, 1, __LINE__);
    316 
    317   AboutToNavigateRenderView();
    318   base::RunLoop().RunUntilIdle();
    319   ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED,
    320             download_request_limiter_->GetDownloadStatus(web_contents()));
    321   CanDownload();
    322   ExpectAndResetCounts(0, 1, 0, __LINE__);
    323   ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED,
    324             download_request_limiter_->GetDownloadStatus(web_contents()));
    325 }
    326 
    327 TEST_F(DownloadRequestLimiterTest,
    328        DownloadRequestLimiter_RawWebContents) {
    329   scoped_ptr<WebContents> web_contents(CreateTestWebContents());
    330   // DownloadRequestLimiter won't try to make an infobar if it doesn't have an
    331   // InfoBarService, and we want to test that it will Cancel() instead of
    332   // prompting when it doesn't have a InfoBarService, so unset the delegate.
    333   UnsetDelegate();
    334   ExpectAndResetCounts(0, 0, 0, __LINE__);
    335   EXPECT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD,
    336             download_request_limiter_->GetDownloadStatus(web_contents.get()));
    337   // You get one freebie.
    338   CanDownloadFor(web_contents.get());
    339   ExpectAndResetCounts(1, 0, 0, __LINE__);
    340   EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD,
    341             download_request_limiter_->GetDownloadStatus(web_contents.get()));
    342   OnUserGestureFor(web_contents.get());
    343   EXPECT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD,
    344             download_request_limiter_->GetDownloadStatus(web_contents.get()));
    345   CanDownloadFor(web_contents.get());
    346   ExpectAndResetCounts(1, 0, 0, __LINE__);
    347   EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD,
    348             download_request_limiter_->GetDownloadStatus(web_contents.get()));
    349   CanDownloadFor(web_contents.get());
    350   ExpectAndResetCounts(0, 1, 0, __LINE__);
    351   EXPECT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED,
    352             download_request_limiter_->GetDownloadStatus(web_contents.get()));
    353   OnUserGestureFor(web_contents.get());
    354   EXPECT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD,
    355             download_request_limiter_->GetDownloadStatus(web_contents.get()));
    356   CanDownloadFor(web_contents.get());
    357   ExpectAndResetCounts(1, 0, 0, __LINE__);
    358   EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD,
    359             download_request_limiter_->GetDownloadStatus(web_contents.get()));
    360 }
    361 
    362 TEST_F(DownloadRequestLimiterTest,
    363        DownloadRequestLimiter_SetHostContentSetting) {
    364   NavigateAndCommit(GURL("http://foo.com/bar"));
    365   SetHostContentSetting(web_contents(), CONTENT_SETTING_ALLOW);
    366 
    367   CanDownload();
    368   ExpectAndResetCounts(1, 0, 0, __LINE__);
    369   ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD,
    370             download_request_limiter_->GetDownloadStatus(web_contents()));
    371 
    372   CanDownload();
    373   ExpectAndResetCounts(1, 0, 0, __LINE__);
    374   ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD,
    375             download_request_limiter_->GetDownloadStatus(web_contents()));
    376 
    377   SetHostContentSetting(web_contents(), CONTENT_SETTING_BLOCK);
    378 
    379   CanDownload();
    380   ExpectAndResetCounts(0, 1, 0, __LINE__);
    381   ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD,
    382             download_request_limiter_->GetDownloadStatus(web_contents()));
    383 
    384   CanDownload();
    385   ExpectAndResetCounts(0, 1, 0, __LINE__);
    386   ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD,
    387             download_request_limiter_->GetDownloadStatus(web_contents()));
    388 }
    389