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