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