blob: 308fc2fe36a1ae04707dc55715863968f3e0a57e [file] [log] [blame]
// Copyright (c) 2011 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 "chrome/browser/safe_browsing/download_protection_service.h"
#include <map>
#include <string>
#include "base/bind.h"
#include "base/callback.h"
#include "base/memory/ref_counted.h"
#include "base/memory/scoped_ptr.h"
#include "base/message_loop.h"
#include "chrome/common/safe_browsing/csd.pb.h"
#include "chrome/browser/safe_browsing/safe_browsing_service.h"
#include "content/browser/browser_thread.h"
#include "content/common/net/url_fetcher.h"
#include "content/test/test_url_fetcher_factory.h"
#include "googleurl/src/gurl.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
using ::testing::Return;
using ::testing::_;
namespace safe_browsing {
namespace {
class MockSafeBrowsingService : public SafeBrowsingService {
public:
MockSafeBrowsingService() {}
virtual ~MockSafeBrowsingService() {}
MOCK_METHOD1(MatchDownloadWhitelistUrl, bool(const GURL&));
private:
DISALLOW_COPY_AND_ASSIGN(MockSafeBrowsingService);
};
} // namespace
class DownloadProtectionServiceTest : public testing::Test {
protected:
virtual void SetUp() {
ui_thread_.reset(new BrowserThread(BrowserThread::UI, &msg_loop_));
io_thread_.reset(new BrowserThread(BrowserThread::IO, &msg_loop_));
sb_service_ = new MockSafeBrowsingService();
download_service_ = new DownloadProtectionService(sb_service_.get(),
NULL);
download_service_->SetEnabled(true);
msg_loop_.RunAllPending();
}
virtual void TearDown() {
msg_loop_.RunAllPending();
download_service_ = NULL;
sb_service_ = NULL;
io_thread_.reset();
ui_thread_.reset();
}
bool RequestContainsResource(const ClientDownloadRequest& request,
ClientDownloadRequest::ResourceType type,
const std::string& url,
const std::string& referrer) {
for (int i = 0; i < request.resources_size(); ++i) {
if (request.resources(i).url() == url &&
request.resources(i).type() == type &&
(referrer.empty() || request.resources(i).referrer() == referrer)) {
return true;
}
}
return false;
}
public:
void CheckDoneCallback(
DownloadProtectionService::DownloadCheckResult result) {
result_ = result;
msg_loop_.Quit();
}
protected:
scoped_refptr<MockSafeBrowsingService> sb_service_;
scoped_refptr<DownloadProtectionService> download_service_;
MessageLoop msg_loop_;
DownloadProtectionService::DownloadCheckResult result_;
scoped_ptr<BrowserThread> io_thread_;
scoped_ptr<BrowserThread> ui_thread_;
};
TEST_F(DownloadProtectionServiceTest, CheckClientDownloadInvalidUrl) {
DownloadProtectionService::DownloadInfo info;
EXPECT_TRUE(download_service_->CheckClientDownload(
info,
base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
base::Unretained(this))));
// Only http is supported for now.
info.download_url_chain.push_back(GURL("https://www.google.com/"));
EXPECT_TRUE(download_service_->CheckClientDownload(
info,
base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
base::Unretained(this))));
info.download_url_chain[0] = GURL("ftp://www.google.com/");
EXPECT_TRUE(download_service_->CheckClientDownload(
info,
base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
base::Unretained(this))));
}
TEST_F(DownloadProtectionServiceTest, CheckClientDownloadWhitelistedUrl) {
DownloadProtectionService::DownloadInfo info;
info.download_url_chain.push_back(GURL("http://www.evil.com/bla.exe"));
info.download_url_chain.push_back(GURL("http://www.google.com/a.exe"));
info.referrer_url = GURL("http://www.google.com/");
EXPECT_CALL(*sb_service_, MatchDownloadWhitelistUrl(_))
.WillRepeatedly(Return(false));
EXPECT_CALL(*sb_service_,
MatchDownloadWhitelistUrl(GURL("http://www.google.com/a.exe")))
.WillRepeatedly(Return(true));
EXPECT_FALSE(download_service_->CheckClientDownload(
info,
base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
base::Unretained(this))));
msg_loop_.Run();
EXPECT_EQ(DownloadProtectionService::SAFE, result_);
// Check that the referrer is matched against the whitelist.
info.download_url_chain.pop_back();
info.referrer_url = GURL("http://www.google.com/a.exe");
EXPECT_FALSE(download_service_->CheckClientDownload(
info,
base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
base::Unretained(this))));
msg_loop_.Run();
EXPECT_EQ(DownloadProtectionService::SAFE, result_);
}
TEST_F(DownloadProtectionServiceTest, CheckClientDownloadFetchFailed) {
FakeURLFetcherFactory factory;
// HTTP request will fail.
factory.SetFakeResponse(
DownloadProtectionService::kDownloadRequestUrl, "", false);
EXPECT_CALL(*sb_service_, MatchDownloadWhitelistUrl(_))
.WillRepeatedly(Return(false));
DownloadProtectionService::DownloadInfo info;
info.download_url_chain.push_back(GURL("http://www.evil.com/a.exe"));
info.referrer_url = GURL("http://www.google.com/");
EXPECT_FALSE(download_service_->CheckClientDownload(
info,
base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
base::Unretained(this))));
msg_loop_.Run();
EXPECT_EQ(DownloadProtectionService::SAFE, result_);
}
TEST_F(DownloadProtectionServiceTest, CheckClientDownloadSuccess) {
FakeURLFetcherFactory factory;
// Empty response means SAFE.
factory.SetFakeResponse(
DownloadProtectionService::kDownloadRequestUrl, "", true);
EXPECT_CALL(*sb_service_, MatchDownloadWhitelistUrl(_))
.WillRepeatedly(Return(false));
DownloadProtectionService::DownloadInfo info;
info.download_url_chain.push_back(GURL("http://www.evil.com/a.exe"));
info.referrer_url = GURL("http://www.google.com/");
EXPECT_FALSE(download_service_->CheckClientDownload(
info,
base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
base::Unretained(this))));
msg_loop_.Run();
EXPECT_EQ(DownloadProtectionService::SAFE, result_);
// Invalid response should be safe too.
factory.SetFakeResponse(
DownloadProtectionService::kDownloadRequestUrl, "bla", true);
EXPECT_FALSE(download_service_->CheckClientDownload(
info,
base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
base::Unretained(this))));
msg_loop_.Run();
EXPECT_EQ(DownloadProtectionService::SAFE, result_);
}
TEST_F(DownloadProtectionServiceTest, CheckClientDownloadValidateRequest) {
TestURLFetcherFactory factory;
DownloadProtectionService::DownloadInfo info;
info.download_url_chain.push_back(GURL("http://www.google.com/"));
info.download_url_chain.push_back(GURL("http://www.google.com/bla.exe"));
info.referrer_url = GURL("http://www.google.com/");
info.sha256_hash = "hash";
info.total_bytes = 100;
info.user_initiated = false;
EXPECT_CALL(*sb_service_, MatchDownloadWhitelistUrl(_))
.WillRepeatedly(Return(false));
EXPECT_FALSE(download_service_->CheckClientDownload(
info,
base::Bind(&DownloadProtectionServiceTest::CheckDoneCallback,
base::Unretained(this))));
msg_loop_.RunAllPending(); // Wait until StartCheckClientDownload is called.
ASSERT_TRUE(factory.GetFetcherByID(0));
ClientDownloadRequest request;
EXPECT_TRUE(request.ParseFromString(
factory.GetFetcherByID(0)->upload_data()));
EXPECT_EQ("http://www.google.com/bla.exe", request.url());
EXPECT_EQ(info.sha256_hash, request.digests().sha256());
EXPECT_EQ(info.total_bytes, request.length());
EXPECT_EQ(info.user_initiated, request.user_initiated());
EXPECT_EQ(2, request.resources_size());
EXPECT_TRUE(RequestContainsResource(request,
ClientDownloadRequest::DOWNLOAD_REDIRECT,
"http://www.google.com/", ""));
EXPECT_TRUE(RequestContainsResource(request,
ClientDownloadRequest::DOWNLOAD_URL,
"http://www.google.com/bla.exe",
info.referrer_url.spec()));
}
} // namespace safe_browsing