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