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