// Copyright (c) 2012 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "base/bind.h" #include "chrome/browser/download/download_request_limiter.h" #include "chrome/browser/ui/tab_contents/tab_contents.h" #include "chrome/browser/ui/tab_contents/test_tab_contents.h" #include "chrome/test/base/testing_profile.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/web_contents.h" #include "content/public/test/test_browser_thread.h" #include "testing/gtest/include/gtest/gtest.h" using content::BrowserThread; using content::WebContents; class DownloadRequestLimiterTest : public TabContentsTestHarness { public: DownloadRequestLimiterTest() : ui_thread_(BrowserThread::UI, &message_loop_), file_user_blocking_thread_( BrowserThread::FILE_USER_BLOCKING, &message_loop_), io_thread_(BrowserThread::IO, &message_loop_) { } virtual void SetUp() { TabContentsTestHarness::SetUp(); allow_download_ = true; ask_allow_count_ = cancel_count_ = continue_count_ = 0; download_request_limiter_ = new DownloadRequestLimiter(); test_delegate_.reset(new DownloadRequestLimiterTestDelegate(this)); DownloadRequestLimiter::SetTestingDelegate(test_delegate_.get()); } virtual void TearDown() { UnsetDelegate(); TabContentsTestHarness::TearDown(); } virtual void UnsetDelegate() { DownloadRequestLimiter::SetTestingDelegate(NULL); } void CanDownload() { CanDownloadFor(web_contents()); } void CanDownloadFor(WebContents* web_contents) { download_request_limiter_->CanDownloadImpl( web_contents, -1, // request id "GET", // request method base::Bind(&DownloadRequestLimiterTest::ContinueDownload, base::Unretained(this))); message_loop_.RunAllPending(); } void OnUserGesture() { OnUserGestureFor(web_contents()); } void OnUserGestureFor(WebContents* web_contents) { DownloadRequestLimiter::TabDownloadState* state = download_request_limiter_->GetDownloadState(web_contents, NULL, false); if (state) state->DidGetUserGesture(); } bool ShouldAllowDownload() { ask_allow_count_++; return allow_download_; } protected: void ContinueDownload(bool allow) { if (allow) { continue_count_++; } else { cancel_count_++; } } class DownloadRequestLimiterTestDelegate : public DownloadRequestLimiter::TestingDelegate { public: explicit DownloadRequestLimiterTestDelegate( DownloadRequestLimiterTest* test) : test_(test) { } virtual bool ShouldAllowDownload() { return test_->ShouldAllowDownload(); } private: DownloadRequestLimiterTest* test_; }; scoped_ptr test_delegate_; scoped_refptr download_request_limiter_; // Number of times ContinueDownload was invoked. int continue_count_; // Number of times CancelDownload was invoked. int cancel_count_; // Whether the download should be allowed. bool allow_download_; // Number of times ShouldAllowDownload was invoked. int ask_allow_count_; content::TestBrowserThread ui_thread_; content::TestBrowserThread file_user_blocking_thread_; content::TestBrowserThread io_thread_; }; TEST_F(DownloadRequestLimiterTest, DownloadRequestLimiter_Allow) { // All tabs should initially start at ALLOW_ONE_DOWNLOAD. ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD, download_request_limiter_->GetDownloadStatus(contents())); // Ask if the tab can do a download. This moves to PROMPT_BEFORE_DOWNLOAD. CanDownload(); ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD, download_request_limiter_->GetDownloadStatus(contents())); // We should have been told we can download. ASSERT_EQ(1, continue_count_); ASSERT_EQ(0, cancel_count_); ASSERT_EQ(0, ask_allow_count_); continue_count_ = 0; // Ask again. This triggers asking the delegate for allow/disallow. allow_download_ = true; CanDownload(); // This should ask us if the download is allowed. ASSERT_EQ(1, ask_allow_count_); ask_allow_count_ = 0; ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS, download_request_limiter_->GetDownloadStatus(contents())); // We should have been told we can download. ASSERT_EQ(1, continue_count_); ASSERT_EQ(0, cancel_count_); continue_count_ = 0; // Ask again and make sure continue is invoked. CanDownload(); // The state is at allow_all, which means the delegate shouldn't be asked. ASSERT_EQ(0, ask_allow_count_); ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS, download_request_limiter_->GetDownloadStatus(contents())); // We should have been told we can download. ASSERT_EQ(1, continue_count_); ASSERT_EQ(0, cancel_count_); continue_count_ = 0; } TEST_F(DownloadRequestLimiterTest, DownloadRequestLimiter_ResetOnNavigation) { NavigateAndCommit(GURL("http://foo.com/bar")); // Do two downloads, allowing the second so that we end up with allow all. CanDownload(); allow_download_ = true; CanDownload(); ask_allow_count_ = continue_count_ = cancel_count_ = 0; ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS, download_request_limiter_->GetDownloadStatus(contents())); // Navigate to a new URL with the same host, which shouldn't reset the allow // all state. NavigateAndCommit(GURL("http://foo.com/bar2")); CanDownload(); ASSERT_EQ(1, continue_count_); ASSERT_EQ(0, cancel_count_); ASSERT_EQ(0, ask_allow_count_); ask_allow_count_ = continue_count_ = cancel_count_ = 0; ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS, download_request_limiter_->GetDownloadStatus(contents())); // Do a user gesture, because we're at allow all, this shouldn't change the // state. OnUserGesture(); ASSERT_EQ(DownloadRequestLimiter::ALLOW_ALL_DOWNLOADS, download_request_limiter_->GetDownloadStatus(contents())); // Navigate to a completely different host, which should reset the state. NavigateAndCommit(GURL("http://fooey.com")); ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD, download_request_limiter_->GetDownloadStatus(contents())); } TEST_F(DownloadRequestLimiterTest, DownloadRequestLimiter_ResetOnUserGesture) { NavigateAndCommit(GURL("http://foo.com/bar")); // Do one download, which should change to prompt before download. CanDownload(); ask_allow_count_ = continue_count_ = cancel_count_ = 0; ASSERT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD, download_request_limiter_->GetDownloadStatus(contents())); // Do a user gesture, which should reset back to allow one. OnUserGesture(); ASSERT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD, download_request_limiter_->GetDownloadStatus(contents())); // Ask twice, which triggers calling the delegate. Don't allow the download // so that we end up with not allowed. allow_download_ = false; CanDownload(); CanDownload(); ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED, download_request_limiter_->GetDownloadStatus(contents())); // A user gesture now should NOT change the state. OnUserGesture(); ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED, download_request_limiter_->GetDownloadStatus(contents())); // And make sure we really can't download. ask_allow_count_ = continue_count_ = cancel_count_ = 0; CanDownload(); ASSERT_EQ(0, ask_allow_count_); ASSERT_EQ(0, continue_count_); ASSERT_EQ(1, cancel_count_); // And the state shouldn't have changed. ASSERT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED, download_request_limiter_->GetDownloadStatus(contents())); } TEST_F(DownloadRequestLimiterTest, DownloadRequestLimiter_RawWebContents) { // By-pass TabContentsTestHarness and use // RenderViewHostTestHarness::CreateTestWebContents() directly so that there // will be no TabContents for web_contents. scoped_ptr web_contents(CreateTestWebContents()); TabContents* tab_contents = TabContents::FromWebContents(web_contents.get()); ASSERT_TRUE(tab_contents == NULL); // DownloadRequestLimiter won't try to make an infobar if it doesn't have a // TabContents, and we want to test that it will Cancel() instead of prompting // when it doesn't have a TabContents, so unset the delegate. UnsetDelegate(); EXPECT_EQ(0, continue_count_); EXPECT_EQ(0, cancel_count_); EXPECT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD, download_request_limiter_->GetDownloadStatus(web_contents.get())); // You get one freebie. CanDownloadFor(web_contents.get()); EXPECT_EQ(1, continue_count_); EXPECT_EQ(0, cancel_count_); EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD, download_request_limiter_->GetDownloadStatus(web_contents.get())); OnUserGestureFor(web_contents.get()); EXPECT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD, download_request_limiter_->GetDownloadStatus(web_contents.get())); CanDownloadFor(web_contents.get()); EXPECT_EQ(2, continue_count_); EXPECT_EQ(0, cancel_count_); EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD, download_request_limiter_->GetDownloadStatus(web_contents.get())); CanDownloadFor(web_contents.get()); EXPECT_EQ(2, continue_count_); EXPECT_EQ(1, cancel_count_); EXPECT_EQ(DownloadRequestLimiter::DOWNLOADS_NOT_ALLOWED, download_request_limiter_->GetDownloadStatus(web_contents.get())); OnUserGestureFor(web_contents.get()); EXPECT_EQ(DownloadRequestLimiter::ALLOW_ONE_DOWNLOAD, download_request_limiter_->GetDownloadStatus(web_contents.get())); CanDownloadFor(web_contents.get()); EXPECT_EQ(3, continue_count_); EXPECT_EQ(1, cancel_count_); EXPECT_EQ(DownloadRequestLimiter::PROMPT_BEFORE_DOWNLOAD, download_request_limiter_->GetDownloadStatus(web_contents.get())); }