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