1ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen// Copyright (c) 2011 The Chromium Authors. All rights reserved. 24a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// Use of this source code is governed by a BSD-style license that can be 34a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch// found in the LICENSE file. 44a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 54a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include <map> 672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include <queue> 74a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include <string> 84a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 94a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/callback.h" 104a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/file_path.h" 114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/file_util.h" 124a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/file_util_proxy.h" 134a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/logging.h" 14ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_ptr.h" 15ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "base/memory/scoped_temp_dir.h" 164a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/message_loop.h" 174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/platform_file.h" 184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "base/task.h" 1972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen#include "base/time.h" 204a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/browser/safe_browsing/client_side_detection_service.h" 214a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/common/net/test_url_fetcher_factory.h" 224a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "chrome/common/net/url_fetcher.h" 23ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen#include "chrome/common/safe_browsing/csd.pb.h" 24dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "content/browser/browser_thread.h" 254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "googleurl/src/gurl.h" 264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch#include "net/url_request/url_request_status.h" 27dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen#include "testing/gtest/include/gtest/gtest.h" 284a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 294a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochnamespace safe_browsing { 304a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 314a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdochclass ClientSideDetectionServiceTest : public testing::Test { 324a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch protected: 334a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch virtual void SetUp() { 344a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch file_thread_.reset(new BrowserThread(BrowserThread::FILE, &msg_loop_)); 354a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch factory_.reset(new FakeURLFetcherFactory()); 374a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch URLFetcher::set_factory(factory_.get()); 384a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 394a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch browser_thread_.reset(new BrowserThread(BrowserThread::UI, &msg_loop_)); 404a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 414a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch virtual void TearDown() { 434a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch msg_loop_.RunAllPending(); 444a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch csd_service_.reset(); 454a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch URLFetcher::set_factory(NULL); 464a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch file_thread_.reset(); 474a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch browser_thread_.reset(); 484a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 494a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 504a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch base::PlatformFile GetModelFile() { 514a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch model_file_ = base::kInvalidPlatformFileValue; 524a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch csd_service_->GetModelFile(NewCallback( 534a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch this, &ClientSideDetectionServiceTest::GetModelFileDone)); 544a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // This method will block this thread until GetModelFileDone is called. 554a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch msg_loop_.Run(); 564a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return model_file_; 574a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 584a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 594a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch std::string ReadModelFile(base::PlatformFile model_file) { 604a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch char buf[1024]; 614a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch int n = base::ReadPlatformFile(model_file, 0, buf, 1024); 624a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch EXPECT_LE(0, n); 634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return (n < 0) ? "" : std::string(buf, n); 644a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 654a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 664a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch bool SendClientReportPhishingRequest(const GURL& phishing_url, 67ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen float score) { 68ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen ClientPhishingRequest* request = new ClientPhishingRequest(); 69ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen request->set_url(phishing_url.spec()); 70ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen request->set_client_score(score); 71ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen request->set_is_phishing(true); // client thinks the URL is phishing. 724a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch csd_service_->SendClientReportPhishingRequest( 73ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen request, 744a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch NewCallback(this, &ClientSideDetectionServiceTest::SendRequestDone)); 754a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch phishing_url_ = phishing_url; 764a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch msg_loop_.Run(); // Waits until callback is called. 774a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch return is_phishing_; 784a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 794a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 804a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch void SetModelFetchResponse(std::string response_data, bool success) { 814a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch factory_->SetFakeResponse(ClientSideDetectionService::kClientModelUrl, 824a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch response_data, success); 834a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 844a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 854a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch void SetClientReportPhishingResponse(std::string response_data, 864a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch bool success) { 874a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch factory_->SetFakeResponse( 884a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch ClientSideDetectionService::kClientReportPhishingUrl, 894a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch response_data, success); 904a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 914a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 9272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen int GetNumReports() { 9372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return csd_service_->GetNumReports(); 9472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 9572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 9672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen std::queue<base::Time>& GetPhishingReportTimes() { 9772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen return csd_service_->phishing_report_times_; 9872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 9972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 10072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen void SetCache(const GURL& gurl, bool is_phishing, base::Time time) { 10172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen csd_service_->cache_[gurl] = 10272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen make_linked_ptr(new ClientSideDetectionService::CacheState(is_phishing, 10372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen time)); 10472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 10572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 10672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen void TestCache() { 10772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ClientSideDetectionService::PhishingCache& cache = csd_service_->cache_; 10872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::Time now = base::Time::Now(); 10972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::Time time = now - ClientSideDetectionService::kNegativeCacheInterval + 11072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::TimeDelta::FromMinutes(5); 11172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen cache[GURL("http://first.url.com/")] = 11272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen make_linked_ptr(new ClientSideDetectionService::CacheState(false, 11372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen time)); 11472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 11572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen time = now - ClientSideDetectionService::kNegativeCacheInterval - 11672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::TimeDelta::FromHours(1); 11772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen cache[GURL("http://second.url.com/")] = 11872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen make_linked_ptr(new ClientSideDetectionService::CacheState(false, 11972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen time)); 12072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 12172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen time = now - ClientSideDetectionService::kPositiveCacheInterval - 12272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::TimeDelta::FromMinutes(5); 12372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen cache[GURL("http://third.url.com/")] = 12472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen make_linked_ptr(new ClientSideDetectionService::CacheState(true, time)); 12572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 12672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen time = now - ClientSideDetectionService::kPositiveCacheInterval + 12772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::TimeDelta::FromMinutes(5); 12872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen cache[GURL("http://fourth.url.com/")] = 12972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen make_linked_ptr(new ClientSideDetectionService::CacheState(true, time)); 13072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 13172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen csd_service_->UpdateCache(); 13272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 13372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // 3 elements should be in the cache, the first, third, and fourth. 13472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen EXPECT_EQ(3U, cache.size()); 13572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen EXPECT_TRUE(cache.find(GURL("http://first.url.com/")) != cache.end()); 13672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen EXPECT_TRUE(cache.find(GURL("http://third.url.com/")) != cache.end()); 13772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen EXPECT_TRUE(cache.find(GURL("http://fourth.url.com/")) != cache.end()); 13872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 13972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // While 3 elements remain, only the first and the fourth are actually 14072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen // valid. 14172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen bool is_phishing; 142ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen EXPECT_TRUE(csd_service_->GetValidCachedResult( 143ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen GURL("http://first.url.com"), &is_phishing)); 14472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen EXPECT_FALSE(is_phishing); 145ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen EXPECT_FALSE(csd_service_->GetValidCachedResult( 146ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen GURL("http://third.url.com"), &is_phishing)); 147ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen EXPECT_TRUE(csd_service_->GetValidCachedResult( 148ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen GURL("http://fourth.url.com"), &is_phishing)); 14972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen EXPECT_TRUE(is_phishing); 15072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 15172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 1524a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch protected: 1534a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch scoped_ptr<ClientSideDetectionService> csd_service_; 1544a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch scoped_ptr<FakeURLFetcherFactory> factory_; 1554a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch MessageLoop msg_loop_; 1564a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1574a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch private: 1584a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch void GetModelFileDone(base::PlatformFile model_file) { 1594a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch model_file_ = model_file; 1604a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch msg_loop_.Quit(); 1614a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 1624a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1634a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch void SendRequestDone(GURL phishing_url, bool is_phishing) { 1644a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch ASSERT_EQ(phishing_url, phishing_url_); 1654a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch is_phishing_ = is_phishing; 1664a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch msg_loop_.Quit(); 1674a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch } 1684a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1694a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch scoped_ptr<BrowserThread> browser_thread_; 1704a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch base::PlatformFile model_file_; 1714a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch scoped_ptr<BrowserThread> file_thread_; 1724a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1734a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch GURL phishing_url_; 1744a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch bool is_phishing_; 1754a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch}; 1764a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1774a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben MurdochTEST_F(ClientSideDetectionServiceTest, TestFetchingModel) { 1784a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch ScopedTempDir tmp_dir; 1794a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch ASSERT_TRUE(tmp_dir.CreateUniqueTempDir()); 1804a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch FilePath model_path = tmp_dir.path().AppendASCII("model"); 1814a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1824a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // The first time we create the csd service the model file does not exist so 1834a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // we expect there to be a fetch. 1844a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch SetModelFetchResponse("BOGUS MODEL", true); 1854a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch csd_service_.reset(ClientSideDetectionService::Create(model_path, NULL)); 1864a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch base::PlatformFile model_file = GetModelFile(); 1874a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch EXPECT_NE(model_file, base::kInvalidPlatformFileValue); 1884a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch EXPECT_EQ(ReadModelFile(model_file), "BOGUS MODEL"); 1894a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1904a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // If you call GetModelFile() multiple times you always get the same platform 1914a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // file back. We don't re-open the file. 1924a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch EXPECT_EQ(GetModelFile(), model_file); 1934a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 1944a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // The second time the model already exists on disk. In this case there 1954a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // should not be any fetch. To ensure that we clear the factory. 1964a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch factory_->ClearFakeReponses(); 1974a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch csd_service_.reset(ClientSideDetectionService::Create(model_path, NULL)); 1984a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch model_file = GetModelFile(); 1994a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch EXPECT_NE(model_file, base::kInvalidPlatformFileValue); 2004a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch EXPECT_EQ(ReadModelFile(model_file), "BOGUS MODEL"); 2014a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 2024a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // If the model does not exist and the fetch fails we should get an error. 2034a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch model_path = tmp_dir.path().AppendASCII("another_model"); 2044a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch SetModelFetchResponse("", false /* success */); 2054a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch csd_service_.reset(ClientSideDetectionService::Create(model_path, NULL)); 2064a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch EXPECT_EQ(GetModelFile(), base::kInvalidPlatformFileValue); 2074a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 2084a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 2094a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben MurdochTEST_F(ClientSideDetectionServiceTest, ServiceObjectDeletedBeforeCallbackDone) { 2104a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch SetModelFetchResponse("bogus model", true /* success */); 2114a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch ScopedTempDir tmp_dir; 2124a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch ASSERT_TRUE(tmp_dir.CreateUniqueTempDir()); 2134a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch csd_service_.reset(ClientSideDetectionService::Create( 2144a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch tmp_dir.path().AppendASCII("model"), NULL)); 2154a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch EXPECT_TRUE(csd_service_.get() != NULL); 2164a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // We delete the client-side detection service class even though the callbacks 2174a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // haven't run yet. 2184a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch csd_service_.reset(); 2194a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // Waiting for the callbacks to run should not crash even if the service 2204a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // object is gone. 2214a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch msg_loop_.RunAllPending(); 2224a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 2234a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 2244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben MurdochTEST_F(ClientSideDetectionServiceTest, SendClientReportPhishingRequest) { 2254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch SetModelFetchResponse("bogus model", true /* success */); 2264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch ScopedTempDir tmp_dir; 2274a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch ASSERT_TRUE(tmp_dir.CreateUniqueTempDir()); 2284a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch csd_service_.reset(ClientSideDetectionService::Create( 2294a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch tmp_dir.path().AppendASCII("model"), NULL)); 2304a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 2314a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch GURL url("http://a.com/"); 232ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen float score = 0.4f; // Some random client score. 2334a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 23472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::Time before = base::Time::Now(); 2354a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 2364a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // Invalid response body from the server. 2374a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch SetClientReportPhishingResponse("invalid proto response", true /* success */); 23872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen EXPECT_FALSE(SendClientReportPhishingRequest(url, score)); 2394a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 2404a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch // Normal behavior. 2414a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch ClientPhishingResponse response; 2424a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch response.set_phishy(true); 2434a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch SetClientReportPhishingResponse(response.SerializeAsString(), 2444a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch true /* success */); 24572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen EXPECT_TRUE(SendClientReportPhishingRequest(url, score)); 24672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 247ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // This request will fail 24872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen GURL second_url("http://b.com/"); 24972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen response.set_phishy(false); 25072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen SetClientReportPhishingResponse(response.SerializeAsString(), 25172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen false /* success*/); 25272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen EXPECT_FALSE(SendClientReportPhishingRequest(second_url, score)); 25372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 25472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::Time after = base::Time::Now(); 25572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 256ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Check that we have recorded all 3 requests within the correct time range. 25772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen std::queue<base::Time>& report_times = GetPhishingReportTimes(); 258ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen EXPECT_EQ(3U, report_times.size()); 25972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen while (!report_times.empty()) { 26072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::Time time = report_times.back(); 26172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen report_times.pop(); 26272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen EXPECT_LE(before, time); 26372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen EXPECT_GE(after, time); 26472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen } 265ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen 266ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen // Only the first url should be in the cache. 267ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen bool is_phishing; 268ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen EXPECT_TRUE(csd_service_->IsInCache(url)); 269ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen EXPECT_TRUE(csd_service_->GetValidCachedResult(url, &is_phishing)); 270ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen EXPECT_TRUE(is_phishing); 271ddb351dbec246cf1fab5ec20d2d5520909041de1Kristian Monsen EXPECT_FALSE(csd_service_->IsInCache(second_url)); 27272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 27372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 27472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenTEST_F(ClientSideDetectionServiceTest, GetNumReportTest) { 27572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen SetModelFetchResponse("bogus model", true /* success */); 27672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ScopedTempDir tmp_dir; 27772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ASSERT_TRUE(tmp_dir.CreateUniqueTempDir()); 27872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen csd_service_.reset(ClientSideDetectionService::Create( 27972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen tmp_dir.path().AppendASCII("model"), NULL)); 28072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 28172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen std::queue<base::Time>& report_times = GetPhishingReportTimes(); 28272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::Time now = base::Time::Now(); 28372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen base::TimeDelta twenty_five_hours = base::TimeDelta::FromHours(25); 28472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen report_times.push(now - twenty_five_hours); 28572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen report_times.push(now - twenty_five_hours); 28672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen report_times.push(now); 28772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen report_times.push(now); 28872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 28972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen EXPECT_EQ(2, GetNumReports()); 29072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 29172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 29272a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian MonsenTEST_F(ClientSideDetectionServiceTest, CacheTest) { 29372a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen SetModelFetchResponse("bogus model", true /* success */); 29472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ScopedTempDir tmp_dir; 29572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ASSERT_TRUE(tmp_dir.CreateUniqueTempDir()); 29672a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen csd_service_.reset(ClientSideDetectionService::Create( 29772a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen tmp_dir.path().AppendASCII("model"), NULL)); 29872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 29972a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen TestCache(); 30072a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen} 30172a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 302dc0f95d653279beabeb9817299e2902918ba123eKristian MonsenTEST_F(ClientSideDetectionServiceTest, IsPrivateIPAddress) { 303dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen SetModelFetchResponse("bogus model", true /* success */); 30472a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ScopedTempDir tmp_dir; 30572a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen ASSERT_TRUE(tmp_dir.CreateUniqueTempDir()); 306dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen csd_service_.reset(ClientSideDetectionService::Create( 307dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen tmp_dir.path().AppendASCII("model"), NULL)); 30872a454cd3513ac24fbdd0e0cb9ad70b86a99b801Kristian Monsen 309dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_TRUE(csd_service_->IsPrivateIPAddress("10.1.2.3")); 310dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_TRUE(csd_service_->IsPrivateIPAddress("127.0.0.1")); 311dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_TRUE(csd_service_->IsPrivateIPAddress("172.24.3.4")); 312dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_TRUE(csd_service_->IsPrivateIPAddress("192.168.1.1")); 313dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_TRUE(csd_service_->IsPrivateIPAddress("fc00::")); 314dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_TRUE(csd_service_->IsPrivateIPAddress("fec0::")); 315dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_TRUE(csd_service_->IsPrivateIPAddress("fec0:1:2::3")); 316dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_TRUE(csd_service_->IsPrivateIPAddress("::1")); 317dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 318dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_FALSE(csd_service_->IsPrivateIPAddress("1.2.3.4")); 319dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_FALSE(csd_service_->IsPrivateIPAddress("200.1.1.1")); 320dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_FALSE(csd_service_->IsPrivateIPAddress("2001:0db8:ac10:fe01::")); 321dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen 322dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen // If the address can't be parsed, the default is true. 323dc0f95d653279beabeb9817299e2902918ba123eKristian Monsen EXPECT_TRUE(csd_service_->IsPrivateIPAddress("blah")); 3244a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} 3254a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch 3264a5e2dc747d50c653511c68ccb2cfbfb740bd5a7Ben Murdoch} // namespace safe_browsing 327