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