Home | History | Annotate | Download | only in safe_browsing
      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 <map>
      6 #include <queue>
      7 #include <string>
      8 
      9 #include "base/bind.h"
     10 #include "base/callback.h"
     11 #include "base/logging.h"
     12 #include "base/memory/scoped_ptr.h"
     13 #include "base/message_loop/message_loop.h"
     14 #include "base/time/time.h"
     15 #include "chrome/browser/safe_browsing/client_side_detection_service.h"
     16 #include "chrome/common/safe_browsing/client_model.pb.h"
     17 #include "chrome/common/safe_browsing/csd.pb.h"
     18 #include "content/public/test/test_browser_thread.h"
     19 #include "crypto/sha2.h"
     20 #include "net/http/http_status_code.h"
     21 #include "net/url_request/test_url_fetcher_factory.h"
     22 #include "net/url_request/url_request_status.h"
     23 #include "testing/gmock/include/gmock/gmock.h"
     24 #include "testing/gtest/include/gtest/gtest.h"
     25 #include "url/gurl.h"
     26 
     27 using ::testing::Invoke;
     28 using ::testing::Mock;
     29 using ::testing::StrictMock;
     30 using ::testing::_;
     31 using content::BrowserThread;
     32 
     33 namespace safe_browsing {
     34 namespace {
     35 class MockClientSideDetectionService : public ClientSideDetectionService {
     36  public:
     37   MockClientSideDetectionService() : ClientSideDetectionService(NULL) {}
     38   virtual ~MockClientSideDetectionService() {}
     39 
     40   MOCK_METHOD1(EndFetchModel, void(ClientModelStatus));
     41   MOCK_METHOD1(ScheduleFetchModel, void(int64));
     42 
     43   void Schedule(int64) {
     44     // Ignore the delay when testing.
     45     StartFetchModel();
     46   }
     47 
     48   void Disable(int) {
     49     // Ignore the status.
     50     SetEnabledAndRefreshState(false);
     51   }
     52 
     53  private:
     54   DISALLOW_COPY_AND_ASSIGN(MockClientSideDetectionService);
     55 };
     56 
     57 ACTION(QuitCurrentMessageLoop) {
     58   base::MessageLoop::current()->Quit();
     59 }
     60 
     61 }  // namespace
     62 
     63 class ClientSideDetectionServiceTest : public testing::Test {
     64  protected:
     65   virtual void SetUp() {
     66     file_thread_.reset(new content::TestBrowserThread(BrowserThread::FILE,
     67                                                       &msg_loop_));
     68 
     69     factory_.reset(new net::FakeURLFetcherFactory(NULL));
     70 
     71     browser_thread_.reset(new content::TestBrowserThread(BrowserThread::UI,
     72                                                          &msg_loop_));
     73   }
     74 
     75   virtual void TearDown() {
     76     msg_loop_.RunUntilIdle();
     77     csd_service_.reset();
     78     file_thread_.reset();
     79     browser_thread_.reset();
     80   }
     81 
     82   bool SendClientReportPhishingRequest(const GURL& phishing_url,
     83                                        float score) {
     84     ClientPhishingRequest* request = new ClientPhishingRequest();
     85     request->set_url(phishing_url.spec());
     86     request->set_client_score(score);
     87     request->set_is_phishing(true);  // client thinks the URL is phishing.
     88     csd_service_->SendClientReportPhishingRequest(
     89         request,
     90         base::Bind(&ClientSideDetectionServiceTest::SendRequestDone,
     91                    base::Unretained(this)));
     92     phishing_url_ = phishing_url;
     93     msg_loop_.Run();  // Waits until callback is called.
     94     return is_phishing_;
     95   }
     96 
     97   bool SendClientReportMalwareRequest(const GURL& url) {
     98     scoped_ptr<ClientMalwareRequest> request(new ClientMalwareRequest());
     99     request->set_url(url.spec());
    100     csd_service_->SendClientReportMalwareRequest(
    101         request.release(),
    102         base::Bind(&ClientSideDetectionServiceTest::SendMalwareRequestDone,
    103                    base::Unretained(this)));
    104     phishing_url_ = url;
    105     msg_loop_.Run();  // Waits until callback is called.
    106     return is_malware_;
    107   }
    108 
    109   void SetModelFetchResponse(std::string response_data,
    110                              net::HttpStatusCode response_code,
    111                              net::URLRequestStatus::Status status) {
    112     factory_->SetFakeResponse(GURL(ClientSideDetectionService::kClientModelUrl),
    113                               response_data, response_code, status);
    114   }
    115 
    116   void SetClientReportPhishingResponse(std::string response_data,
    117                                        net::HttpStatusCode response_code,
    118                                        net::URLRequestStatus::Status status) {
    119     factory_->SetFakeResponse(
    120         ClientSideDetectionService::GetClientReportUrl(
    121             ClientSideDetectionService::kClientReportPhishingUrl),
    122         response_data, response_code, status);
    123   }
    124 
    125   void SetClientReportMalwareResponse(std::string response_data,
    126                                       net::HttpStatusCode response_code,
    127                                       net::URLRequestStatus::Status status) {
    128     factory_->SetFakeResponse(
    129         ClientSideDetectionService::GetClientReportUrl(
    130             ClientSideDetectionService::kClientReportMalwareUrl),
    131         response_data, response_code, status);
    132   }
    133 
    134   int GetNumReports(std::queue<base::Time>* report_times) {
    135     return csd_service_->GetNumReports(report_times);
    136   }
    137 
    138   std::queue<base::Time>& GetPhishingReportTimes() {
    139     return csd_service_->phishing_report_times_;
    140   }
    141 
    142   std::queue<base::Time>& GetMalwareReportTimes() {
    143     return csd_service_->malware_report_times_;
    144   }
    145 
    146   void SetCache(const GURL& gurl, bool is_phishing, base::Time time) {
    147     csd_service_->cache_[gurl] =
    148         make_linked_ptr(new ClientSideDetectionService::CacheState(is_phishing,
    149                                                                    time));
    150   }
    151 
    152   void TestCache() {
    153     ClientSideDetectionService::PhishingCache& cache = csd_service_->cache_;
    154     base::Time now = base::Time::Now();
    155     base::Time time =
    156         now - base::TimeDelta::FromDays(
    157             ClientSideDetectionService::kNegativeCacheIntervalDays) +
    158         base::TimeDelta::FromMinutes(5);
    159     cache[GURL("http://first.url.com/")] =
    160         make_linked_ptr(new ClientSideDetectionService::CacheState(false,
    161                                                                    time));
    162 
    163     time =
    164         now - base::TimeDelta::FromDays(
    165             ClientSideDetectionService::kNegativeCacheIntervalDays) -
    166         base::TimeDelta::FromHours(1);
    167     cache[GURL("http://second.url.com/")] =
    168         make_linked_ptr(new ClientSideDetectionService::CacheState(false,
    169                                                                    time));
    170 
    171     time =
    172         now - base::TimeDelta::FromMinutes(
    173             ClientSideDetectionService::kPositiveCacheIntervalMinutes) -
    174         base::TimeDelta::FromMinutes(5);
    175     cache[GURL("http://third.url.com/")] =
    176         make_linked_ptr(new ClientSideDetectionService::CacheState(true, time));
    177 
    178     time =
    179         now - base::TimeDelta::FromMinutes(
    180             ClientSideDetectionService::kPositiveCacheIntervalMinutes) +
    181         base::TimeDelta::FromMinutes(5);
    182     cache[GURL("http://fourth.url.com/")] =
    183         make_linked_ptr(new ClientSideDetectionService::CacheState(true, time));
    184 
    185     csd_service_->UpdateCache();
    186 
    187     // 3 elements should be in the cache, the first, third, and fourth.
    188     EXPECT_EQ(3U, cache.size());
    189     EXPECT_TRUE(cache.find(GURL("http://first.url.com/")) != cache.end());
    190     EXPECT_TRUE(cache.find(GURL("http://third.url.com/")) != cache.end());
    191     EXPECT_TRUE(cache.find(GURL("http://fourth.url.com/")) != cache.end());
    192 
    193     // While 3 elements remain, only the first and the fourth are actually
    194     // valid.
    195     bool is_phishing;
    196     EXPECT_TRUE(csd_service_->GetValidCachedResult(
    197         GURL("http://first.url.com"), &is_phishing));
    198     EXPECT_FALSE(is_phishing);
    199     EXPECT_FALSE(csd_service_->GetValidCachedResult(
    200         GURL("http://third.url.com"), &is_phishing));
    201     EXPECT_TRUE(csd_service_->GetValidCachedResult(
    202         GURL("http://fourth.url.com"), &is_phishing));
    203     EXPECT_TRUE(is_phishing);
    204   }
    205 
    206   void AddFeature(const std::string& name, double value,
    207                   ClientPhishingRequest* request) {
    208     ClientPhishingRequest_Feature* feature = request->add_feature_map();
    209     feature->set_name(name);
    210     feature->set_value(value);
    211   }
    212 
    213   void AddNonModelFeature(const std::string& name, double value,
    214                           ClientPhishingRequest* request) {
    215     ClientPhishingRequest_Feature* feature =
    216         request->add_non_model_feature_map();
    217     feature->set_name(name);
    218     feature->set_value(value);
    219   }
    220 
    221   void CheckConfirmedMalwareUrl(GURL url) {
    222     ASSERT_EQ(confirmed_malware_url_, url);
    223   }
    224 
    225  protected:
    226   scoped_ptr<ClientSideDetectionService> csd_service_;
    227   scoped_ptr<net::FakeURLFetcherFactory> factory_;
    228   base::MessageLoop msg_loop_;
    229 
    230  private:
    231   void SendRequestDone(GURL phishing_url, bool is_phishing) {
    232     ASSERT_EQ(phishing_url, phishing_url_);
    233     is_phishing_ = is_phishing;
    234     msg_loop_.Quit();
    235   }
    236 
    237   void SendMalwareRequestDone(GURL original_url, GURL malware_url,
    238                               bool is_malware) {
    239     ASSERT_EQ(phishing_url_, original_url);
    240     confirmed_malware_url_ = malware_url;
    241     is_malware_ = is_malware;
    242     msg_loop_.Quit();
    243   }
    244 
    245   scoped_ptr<content::TestBrowserThread> browser_thread_;
    246   scoped_ptr<content::TestBrowserThread> file_thread_;
    247 
    248   GURL phishing_url_;
    249   GURL confirmed_malware_url_;
    250   bool is_phishing_;
    251   bool is_malware_;
    252 };
    253 
    254 TEST_F(ClientSideDetectionServiceTest, FetchModelTest) {
    255   // We don't want to use a real service class here because we can't call
    256   // the real EndFetchModel.  It would reschedule a reload which might
    257   // make the test flaky.
    258   MockClientSideDetectionService service;
    259   EXPECT_CALL(service, ScheduleFetchModel(_)).Times(1);
    260   service.SetEnabledAndRefreshState(true);
    261 
    262   // The model fetch failed.
    263   SetModelFetchResponse("blamodel", net::HTTP_INTERNAL_SERVER_ERROR,
    264                         net::URLRequestStatus::FAILED);
    265   EXPECT_CALL(service, EndFetchModel(
    266       ClientSideDetectionService::MODEL_FETCH_FAILED))
    267       .WillOnce(QuitCurrentMessageLoop());
    268   service.StartFetchModel();
    269   msg_loop_.Run();  // EndFetchModel will quit the message loop.
    270   Mock::VerifyAndClearExpectations(&service);
    271 
    272   // Empty model file.
    273   SetModelFetchResponse(std::string(), net::HTTP_OK,
    274                         net::URLRequestStatus::SUCCESS);
    275   EXPECT_CALL(service, EndFetchModel(ClientSideDetectionService::MODEL_EMPTY))
    276       .WillOnce(QuitCurrentMessageLoop());
    277   service.StartFetchModel();
    278   msg_loop_.Run();  // EndFetchModel will quit the message loop.
    279   Mock::VerifyAndClearExpectations(&service);
    280 
    281   // Model is too large.
    282   SetModelFetchResponse(
    283       std::string(ClientSideDetectionService::kMaxModelSizeBytes + 1, 'x'),
    284       net::HTTP_OK, net::URLRequestStatus::SUCCESS);
    285   EXPECT_CALL(service, EndFetchModel(
    286       ClientSideDetectionService::MODEL_TOO_LARGE))
    287       .WillOnce(QuitCurrentMessageLoop());
    288   service.StartFetchModel();
    289   msg_loop_.Run();  // EndFetchModel will quit the message loop.
    290   Mock::VerifyAndClearExpectations(&service);
    291 
    292   // Unable to parse the model file.
    293   SetModelFetchResponse("Invalid model file", net::HTTP_OK,
    294                         net::URLRequestStatus::SUCCESS);
    295   EXPECT_CALL(service, EndFetchModel(
    296       ClientSideDetectionService::MODEL_PARSE_ERROR))
    297       .WillOnce(QuitCurrentMessageLoop());
    298   service.StartFetchModel();
    299   msg_loop_.Run();  // EndFetchModel will quit the message loop.
    300   Mock::VerifyAndClearExpectations(&service);
    301 
    302   // Model that is missing some required fields (missing the version field).
    303   ClientSideModel model;
    304   model.set_max_words_per_term(4);
    305   SetModelFetchResponse(model.SerializePartialAsString(), net::HTTP_OK,
    306                         net::URLRequestStatus::SUCCESS);
    307   EXPECT_CALL(service, EndFetchModel(
    308       ClientSideDetectionService::MODEL_MISSING_FIELDS))
    309       .WillOnce(QuitCurrentMessageLoop());
    310   service.StartFetchModel();
    311   msg_loop_.Run();  // EndFetchModel will quit the message loop.
    312   Mock::VerifyAndClearExpectations(&service);
    313 
    314   // Model that points to hashes that don't exist.
    315   model.set_version(10);
    316   model.add_hashes("bla");
    317   model.add_page_term(1);  // Should be 0 instead of 1.
    318   SetModelFetchResponse(model.SerializePartialAsString(), net::HTTP_OK,
    319                         net::URLRequestStatus::SUCCESS);
    320   EXPECT_CALL(service, EndFetchModel(
    321       ClientSideDetectionService::MODEL_BAD_HASH_IDS))
    322       .WillOnce(QuitCurrentMessageLoop());
    323   service.StartFetchModel();
    324   msg_loop_.Run();  // EndFetchModel will quit the message loop.
    325   Mock::VerifyAndClearExpectations(&service);
    326   model.set_page_term(0, 0);
    327 
    328   // Model version number is wrong.
    329   model.set_version(-1);
    330   SetModelFetchResponse(model.SerializeAsString(), net::HTTP_OK,
    331                         net::URLRequestStatus::SUCCESS);
    332   EXPECT_CALL(service, EndFetchModel(
    333       ClientSideDetectionService::MODEL_INVALID_VERSION_NUMBER))
    334       .WillOnce(QuitCurrentMessageLoop());
    335   service.StartFetchModel();
    336   msg_loop_.Run();  // EndFetchModel will quit the message loop.
    337   Mock::VerifyAndClearExpectations(&service);
    338 
    339   // Normal model.
    340   model.set_version(10);
    341   SetModelFetchResponse(model.SerializeAsString(), net::HTTP_OK,
    342                         net::URLRequestStatus::SUCCESS);
    343   EXPECT_CALL(service, EndFetchModel(
    344       ClientSideDetectionService::MODEL_SUCCESS))
    345       .WillOnce(QuitCurrentMessageLoop());
    346   service.StartFetchModel();
    347   msg_loop_.Run();  // EndFetchModel will quit the message loop.
    348   Mock::VerifyAndClearExpectations(&service);
    349 
    350   // Model version number is decreasing.  Set the model version number of the
    351   // model that is currently loaded in the service object to 11.
    352   service.model_.reset(new ClientSideModel(model));
    353   service.model_->set_version(11);
    354   SetModelFetchResponse(model.SerializeAsString(), net::HTTP_OK,
    355                         net::URLRequestStatus::SUCCESS);
    356   EXPECT_CALL(service, EndFetchModel(
    357       ClientSideDetectionService::MODEL_INVALID_VERSION_NUMBER))
    358       .WillOnce(QuitCurrentMessageLoop());
    359   service.StartFetchModel();
    360   msg_loop_.Run();  // EndFetchModel will quit the message loop.
    361   Mock::VerifyAndClearExpectations(&service);
    362 
    363   // Model version hasn't changed since the last reload.
    364   service.model_->set_version(10);
    365   SetModelFetchResponse(model.SerializeAsString(), net::HTTP_OK,
    366                         net::URLRequestStatus::SUCCESS);
    367   EXPECT_CALL(service, EndFetchModel(
    368       ClientSideDetectionService::MODEL_NOT_CHANGED))
    369       .WillOnce(QuitCurrentMessageLoop());
    370   service.StartFetchModel();
    371   msg_loop_.Run();  // EndFetchModel will quit the message loop.
    372   Mock::VerifyAndClearExpectations(&service);
    373 }
    374 
    375 TEST_F(ClientSideDetectionServiceTest, ServiceObjectDeletedBeforeCallbackDone) {
    376   SetModelFetchResponse("bogus model", net::HTTP_OK,
    377                         net::URLRequestStatus::SUCCESS);
    378   csd_service_.reset(ClientSideDetectionService::Create(NULL));
    379   csd_service_->SetEnabledAndRefreshState(true);
    380   EXPECT_TRUE(csd_service_.get() != NULL);
    381   // We delete the client-side detection service class even though the callbacks
    382   // haven't run yet.
    383   csd_service_.reset();
    384   // Waiting for the callbacks to run should not crash even if the service
    385   // object is gone.
    386   msg_loop_.RunUntilIdle();
    387 }
    388 
    389 TEST_F(ClientSideDetectionServiceTest, SendClientReportPhishingRequest) {
    390   SetModelFetchResponse("bogus model", net::HTTP_OK,
    391                         net::URLRequestStatus::SUCCESS);
    392   csd_service_.reset(ClientSideDetectionService::Create(NULL));
    393   csd_service_->SetEnabledAndRefreshState(true);
    394 
    395   GURL url("http://a.com/");
    396   float score = 0.4f;  // Some random client score.
    397 
    398   base::Time before = base::Time::Now();
    399 
    400   // Invalid response body from the server.
    401   SetClientReportPhishingResponse("invalid proto response", net::HTTP_OK,
    402                                   net::URLRequestStatus::SUCCESS);
    403   EXPECT_FALSE(SendClientReportPhishingRequest(url, score));
    404 
    405   // Normal behavior.
    406   ClientPhishingResponse response;
    407   response.set_phishy(true);
    408   SetClientReportPhishingResponse(response.SerializeAsString(), net::HTTP_OK,
    409                                   net::URLRequestStatus::SUCCESS);
    410   EXPECT_TRUE(SendClientReportPhishingRequest(url, score));
    411 
    412   // This request will fail
    413   GURL second_url("http://b.com/");
    414   response.set_phishy(false);
    415   SetClientReportPhishingResponse(response.SerializeAsString(),
    416                                   net::HTTP_INTERNAL_SERVER_ERROR,
    417                                   net::URLRequestStatus::FAILED);
    418   EXPECT_FALSE(SendClientReportPhishingRequest(second_url, score));
    419 
    420   base::Time after = base::Time::Now();
    421 
    422   // Check that we have recorded all 3 requests within the correct time range.
    423   std::queue<base::Time>& report_times = GetPhishingReportTimes();
    424   EXPECT_EQ(3U, report_times.size());
    425   while (!report_times.empty()) {
    426     base::Time time = report_times.back();
    427     report_times.pop();
    428     EXPECT_LE(before, time);
    429     EXPECT_GE(after, time);
    430   }
    431 
    432   // Only the first url should be in the cache.
    433   bool is_phishing;
    434   EXPECT_TRUE(csd_service_->IsInCache(url));
    435   EXPECT_TRUE(csd_service_->GetValidCachedResult(url, &is_phishing));
    436   EXPECT_TRUE(is_phishing);
    437   EXPECT_FALSE(csd_service_->IsInCache(second_url));
    438 }
    439 
    440 TEST_F(ClientSideDetectionServiceTest, SendClientReportMalwareRequest) {
    441   SetModelFetchResponse("bogus model", net::HTTP_OK,
    442                         net::URLRequestStatus::SUCCESS);
    443   csd_service_.reset(ClientSideDetectionService::Create(NULL));
    444   csd_service_->SetEnabledAndRefreshState(true);
    445   GURL url("http://a.com/");
    446 
    447   base::Time before = base::Time::Now();
    448   // Invalid response body from the server.
    449   SetClientReportMalwareResponse("invalid proto response", net::HTTP_OK,
    450                                  net::URLRequestStatus::SUCCESS);
    451   EXPECT_FALSE(SendClientReportMalwareRequest(url));
    452 
    453   // Missing bad_url.
    454   ClientMalwareResponse response;
    455   response.set_blacklist(true);
    456   SetClientReportMalwareResponse(response.SerializeAsString(), net::HTTP_OK,
    457                                  net::URLRequestStatus::SUCCESS);
    458   EXPECT_FALSE(SendClientReportMalwareRequest(url));
    459 
    460   // Normal behavior.
    461   response.set_blacklist(true);
    462   response.set_bad_url("http://response-bad.com/");
    463   SetClientReportMalwareResponse(response.SerializeAsString(), net::HTTP_OK,
    464                                  net::URLRequestStatus::SUCCESS);
    465   EXPECT_TRUE(SendClientReportMalwareRequest(url));
    466   CheckConfirmedMalwareUrl(GURL("http://response-bad.com/"));
    467 
    468   // This request will fail
    469   response.set_blacklist(false);
    470   SetClientReportMalwareResponse(response.SerializeAsString(),
    471                                  net::HTTP_INTERNAL_SERVER_ERROR,
    472                                  net::URLRequestStatus::FAILED);
    473   EXPECT_FALSE(SendClientReportMalwareRequest(url));
    474 
    475   // Server blacklist decision is false, and response is successful
    476   response.set_blacklist(false);
    477   SetClientReportMalwareResponse(response.SerializeAsString(), net::HTTP_OK,
    478                                  net::URLRequestStatus::SUCCESS);
    479   EXPECT_FALSE(SendClientReportMalwareRequest(url));
    480 
    481   // Check that we have recorded all 5 requests within the correct time range.
    482   base::Time after = base::Time::Now();
    483   std::queue<base::Time>& report_times = GetMalwareReportTimes();
    484   EXPECT_EQ(5U, report_times.size());
    485 
    486   // Check that the malware report limit was reached.
    487   EXPECT_TRUE(csd_service_->OverMalwareReportLimit());
    488 
    489   report_times = GetMalwareReportTimes();
    490   EXPECT_EQ(5U, report_times.size());
    491   while (!report_times.empty()) {
    492     base::Time time = report_times.back();
    493     report_times.pop();
    494     EXPECT_LE(before, time);
    495     EXPECT_GE(after, time);
    496   }
    497 }
    498 
    499 TEST_F(ClientSideDetectionServiceTest, GetNumReportTest) {
    500   SetModelFetchResponse("bogus model", net::HTTP_OK,
    501                         net::URLRequestStatus::SUCCESS);
    502   csd_service_.reset(ClientSideDetectionService::Create(NULL));
    503 
    504   std::queue<base::Time>& report_times = GetPhishingReportTimes();
    505   base::Time now = base::Time::Now();
    506   base::TimeDelta twenty_five_hours = base::TimeDelta::FromHours(25);
    507   report_times.push(now - twenty_five_hours);
    508   report_times.push(now - twenty_five_hours);
    509   report_times.push(now);
    510   report_times.push(now);
    511 
    512   EXPECT_EQ(2, GetNumReports(&report_times));
    513 }
    514 
    515 TEST_F(ClientSideDetectionServiceTest, CacheTest) {
    516   SetModelFetchResponse("bogus model", net::HTTP_OK,
    517                         net::URLRequestStatus::SUCCESS);
    518   csd_service_.reset(ClientSideDetectionService::Create(NULL));
    519 
    520   TestCache();
    521 }
    522 
    523 TEST_F(ClientSideDetectionServiceTest, IsPrivateIPAddress) {
    524   SetModelFetchResponse("bogus model", net::HTTP_OK,
    525                         net::URLRequestStatus::SUCCESS);
    526   csd_service_.reset(ClientSideDetectionService::Create(NULL));
    527 
    528   EXPECT_TRUE(csd_service_->IsPrivateIPAddress("10.1.2.3"));
    529   EXPECT_TRUE(csd_service_->IsPrivateIPAddress("127.0.0.1"));
    530   EXPECT_TRUE(csd_service_->IsPrivateIPAddress("172.24.3.4"));
    531   EXPECT_TRUE(csd_service_->IsPrivateIPAddress("192.168.1.1"));
    532   EXPECT_TRUE(csd_service_->IsPrivateIPAddress("fc00::"));
    533   EXPECT_TRUE(csd_service_->IsPrivateIPAddress("fec0::"));
    534   EXPECT_TRUE(csd_service_->IsPrivateIPAddress("fec0:1:2::3"));
    535   EXPECT_TRUE(csd_service_->IsPrivateIPAddress("::1"));
    536 
    537   EXPECT_FALSE(csd_service_->IsPrivateIPAddress("1.2.3.4"));
    538   EXPECT_FALSE(csd_service_->IsPrivateIPAddress("200.1.1.1"));
    539   EXPECT_FALSE(csd_service_->IsPrivateIPAddress("2001:0db8:ac10:fe01::"));
    540 
    541   // If the address can't be parsed, the default is true.
    542   EXPECT_TRUE(csd_service_->IsPrivateIPAddress("blah"));
    543 }
    544 
    545 TEST_F(ClientSideDetectionServiceTest, SetBadSubnets) {
    546   ClientSideModel model;
    547   ClientSideDetectionService::BadSubnetMap bad_subnets;
    548   ClientSideDetectionService::SetBadSubnets(model, &bad_subnets);
    549   EXPECT_EQ(0U, bad_subnets.size());
    550 
    551   // Bad subnets are skipped.
    552   ClientSideModel::IPSubnet* subnet = model.add_bad_subnet();
    553   subnet->set_prefix(std::string(crypto::kSHA256Length, '.'));
    554   subnet->set_size(130);  // Invalid size.
    555 
    556   subnet = model.add_bad_subnet();
    557   subnet->set_prefix(std::string(crypto::kSHA256Length, '.'));
    558   subnet->set_size(-1);  // Invalid size.
    559 
    560   subnet = model.add_bad_subnet();
    561   subnet->set_prefix(std::string(16, '.'));  // Invalid len.
    562   subnet->set_size(64);
    563 
    564   ClientSideDetectionService::SetBadSubnets(model, &bad_subnets);
    565   EXPECT_EQ(0U, bad_subnets.size());
    566 
    567   subnet = model.add_bad_subnet();
    568   subnet->set_prefix(std::string(crypto::kSHA256Length, '.'));
    569   subnet->set_size(64);
    570 
    571   subnet = model.add_bad_subnet();
    572   subnet->set_prefix(std::string(crypto::kSHA256Length, ','));
    573   subnet->set_size(64);
    574 
    575   subnet = model.add_bad_subnet();
    576   subnet->set_prefix(std::string(crypto::kSHA256Length, '.'));
    577   subnet->set_size(128);
    578 
    579   subnet = model.add_bad_subnet();
    580   subnet->set_prefix(std::string(crypto::kSHA256Length, '.'));
    581   subnet->set_size(100);
    582 
    583   ClientSideDetectionService::SetBadSubnets(model, &bad_subnets);
    584   EXPECT_EQ(3U, bad_subnets.size());
    585   ClientSideDetectionService::BadSubnetMap::const_iterator it;
    586   std::string mask = std::string(8, '\xFF') + std::string(8, '\x00');
    587   EXPECT_TRUE(bad_subnets.count(mask));
    588   EXPECT_TRUE(bad_subnets[mask].count(std::string(crypto::kSHA256Length, '.')));
    589   EXPECT_TRUE(bad_subnets[mask].count(std::string(crypto::kSHA256Length, ',')));
    590 
    591   mask = std::string(16, '\xFF');
    592   EXPECT_TRUE(bad_subnets.count(mask));
    593   EXPECT_TRUE(bad_subnets[mask].count(std::string(crypto::kSHA256Length, '.')));
    594 
    595   mask = std::string(12, '\xFF') + "\xF0" + std::string(3, '\x00');
    596   EXPECT_TRUE(bad_subnets.count(mask));
    597   EXPECT_TRUE(bad_subnets[mask].count(std::string(crypto::kSHA256Length, '.')));
    598 }
    599 
    600 TEST_F(ClientSideDetectionServiceTest, ModelHasValidHashIds) {
    601   ClientSideModel model;
    602   EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
    603   model.add_hashes("bla");
    604   EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
    605   model.add_page_term(0);
    606   EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
    607 
    608   model.add_page_term(-1);
    609   EXPECT_FALSE(ClientSideDetectionService::ModelHasValidHashIds(model));
    610   model.set_page_term(1, 1);
    611   EXPECT_FALSE(ClientSideDetectionService::ModelHasValidHashIds(model));
    612   model.set_page_term(1, 0);
    613   EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
    614 
    615   // Test bad rules.
    616   model.add_hashes("blu");
    617   ClientSideModel::Rule* rule = model.add_rule();
    618   rule->add_feature(0);
    619   rule->add_feature(1);
    620   rule->set_weight(0.1f);
    621   EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
    622 
    623   rule = model.add_rule();
    624   rule->add_feature(0);
    625   rule->add_feature(1);
    626   rule->add_feature(-1);
    627   rule->set_weight(0.2f);
    628   EXPECT_FALSE(ClientSideDetectionService::ModelHasValidHashIds(model));
    629 
    630   rule->set_feature(2, 2);
    631   EXPECT_FALSE(ClientSideDetectionService::ModelHasValidHashIds(model));
    632 
    633   rule->set_feature(2, 1);
    634   EXPECT_TRUE(ClientSideDetectionService::ModelHasValidHashIds(model));
    635 }
    636 
    637 TEST_F(ClientSideDetectionServiceTest, SetEnabledAndRefreshState) {
    638   // Check that the model isn't downloaded until the service is enabled.
    639   csd_service_.reset(ClientSideDetectionService::Create(NULL));
    640   EXPECT_FALSE(csd_service_->enabled());
    641   EXPECT_TRUE(csd_service_->model_fetcher_.get() == NULL);
    642 
    643   // Use a MockClientSideDetectionService for the rest of the test, to avoid
    644   // the scheduling delay.
    645   MockClientSideDetectionService* service =
    646       new StrictMock<MockClientSideDetectionService>();
    647   csd_service_.reset(service);
    648   EXPECT_FALSE(csd_service_->enabled());
    649   EXPECT_TRUE(csd_service_->model_fetcher_.get() == NULL);
    650   // No calls expected yet.
    651   Mock::VerifyAndClearExpectations(service);
    652 
    653   ClientSideModel model;
    654   model.set_version(10);
    655   model.set_max_words_per_term(4);
    656   SetModelFetchResponse(model.SerializeAsString(), net::HTTP_OK,
    657                         net::URLRequestStatus::SUCCESS);
    658   EXPECT_CALL(*service, ScheduleFetchModel(_))
    659       .WillOnce(Invoke(service, &MockClientSideDetectionService::Schedule));
    660   EXPECT_CALL(*service, EndFetchModel(
    661       ClientSideDetectionService::MODEL_SUCCESS))
    662       .WillOnce(QuitCurrentMessageLoop());
    663   csd_service_->SetEnabledAndRefreshState(true);
    664   EXPECT_TRUE(csd_service_->model_fetcher_.get() != NULL);
    665   msg_loop_.Run();  // EndFetchModel will quit the message loop.
    666   Mock::VerifyAndClearExpectations(service);
    667 
    668   // Check that enabling again doesn't request the model.
    669   csd_service_->SetEnabledAndRefreshState(true);
    670   // No calls expected.
    671   Mock::VerifyAndClearExpectations(service);
    672 
    673   // Check that disabling the service cancels pending requests.
    674   EXPECT_CALL(*service, ScheduleFetchModel(_))
    675       .WillOnce(Invoke(service, &MockClientSideDetectionService::Schedule));
    676   csd_service_->SetEnabledAndRefreshState(false);
    677   csd_service_->SetEnabledAndRefreshState(true);
    678   Mock::VerifyAndClearExpectations(service);
    679   EXPECT_TRUE(csd_service_->model_fetcher_.get() != NULL);
    680   csd_service_->SetEnabledAndRefreshState(false);
    681   EXPECT_TRUE(csd_service_->model_fetcher_.get() == NULL);
    682   msg_loop_.RunUntilIdle();
    683   // No calls expected.
    684   Mock::VerifyAndClearExpectations(service);
    685 
    686   // Requests always return false when the service is disabled.
    687   ClientPhishingResponse response;
    688   response.set_phishy(true);
    689   SetClientReportPhishingResponse(response.SerializeAsString(), net::HTTP_OK,
    690                                   net::URLRequestStatus::SUCCESS);
    691   EXPECT_FALSE(SendClientReportPhishingRequest(GURL("http://a.com/"), 0.4f));
    692 
    693   // Pending requests also return false if the service is disabled before they
    694   // report back.
    695   EXPECT_CALL(*service, ScheduleFetchModel(_))
    696       .WillOnce(Invoke(service, &MockClientSideDetectionService::Schedule));
    697   EXPECT_CALL(*service, EndFetchModel(
    698       ClientSideDetectionService::MODEL_NOT_CHANGED))
    699       .WillOnce(Invoke(service, &MockClientSideDetectionService::Disable));
    700   csd_service_->SetEnabledAndRefreshState(true);
    701   EXPECT_FALSE(SendClientReportPhishingRequest(GURL("http://a.com/"), 0.4f));
    702   Mock::VerifyAndClearExpectations(service);
    703 }
    704 }  // namespace safe_browsing
    705