• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
MockClientSideDetectionService()37   MockClientSideDetectionService() : ClientSideDetectionService(NULL) {}
~MockClientSideDetectionService()38   virtual ~MockClientSideDetectionService() {}
39 
40   MOCK_METHOD1(EndFetchModel, void(ClientModelStatus));
41   MOCK_METHOD1(ScheduleFetchModel, void(int64));
42 
Schedule(int64)43   void Schedule(int64) {
44     // Ignore the delay when testing.
45     StartFetchModel();
46   }
47 
Disable(int)48   void Disable(int) {
49     // Ignore the status.
50     SetEnabledAndRefreshState(false);
51   }
52 
53  private:
54   DISALLOW_COPY_AND_ASSIGN(MockClientSideDetectionService);
55 };
56 
ACTION(QuitCurrentMessageLoop)57 ACTION(QuitCurrentMessageLoop) {
58   base::MessageLoop::current()->Quit();
59 }
60 
61 }  // namespace
62 
63 class ClientSideDetectionServiceTest : public testing::Test {
64  protected:
SetUp()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 
TearDown()75   virtual void TearDown() {
76     msg_loop_.RunUntilIdle();
77     csd_service_.reset();
78     file_thread_.reset();
79     browser_thread_.reset();
80   }
81 
SendClientReportPhishingRequest(const GURL & phishing_url,float score)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 
SendClientReportMalwareRequest(const GURL & url)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 
SetModelFetchResponse(std::string response_data,net::HttpStatusCode response_code,net::URLRequestStatus::Status status)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 
SetClientReportPhishingResponse(std::string response_data,net::HttpStatusCode response_code,net::URLRequestStatus::Status status)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 
SetClientReportMalwareResponse(std::string response_data,net::HttpStatusCode response_code,net::URLRequestStatus::Status status)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 
GetNumReports(std::queue<base::Time> * report_times)134   int GetNumReports(std::queue<base::Time>* report_times) {
135     return csd_service_->GetNumReports(report_times);
136   }
137 
GetPhishingReportTimes()138   std::queue<base::Time>& GetPhishingReportTimes() {
139     return csd_service_->phishing_report_times_;
140   }
141 
GetMalwareReportTimes()142   std::queue<base::Time>& GetMalwareReportTimes() {
143     return csd_service_->malware_report_times_;
144   }
145 
SetCache(const GURL & gurl,bool is_phishing,base::Time time)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 
TestCache()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 
AddFeature(const std::string & name,double value,ClientPhishingRequest * request)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 
AddNonModelFeature(const std::string & name,double value,ClientPhishingRequest * request)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 
CheckConfirmedMalwareUrl(GURL url)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:
SendRequestDone(GURL phishing_url,bool is_phishing)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 
SendMalwareRequestDone(GURL original_url,GURL malware_url,bool is_malware)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 
TEST_F(ClientSideDetectionServiceTest,FetchModelTest)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 
TEST_F(ClientSideDetectionServiceTest,ServiceObjectDeletedBeforeCallbackDone)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 
TEST_F(ClientSideDetectionServiceTest,SendClientReportPhishingRequest)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 
TEST_F(ClientSideDetectionServiceTest,SendClientReportMalwareRequest)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 
TEST_F(ClientSideDetectionServiceTest,GetNumReportTest)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 
TEST_F(ClientSideDetectionServiceTest,CacheTest)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 
TEST_F(ClientSideDetectionServiceTest,IsPrivateIPAddress)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 
TEST_F(ClientSideDetectionServiceTest,SetBadSubnets)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 
TEST_F(ClientSideDetectionServiceTest,ModelHasValidHashIds)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 
TEST_F(ClientSideDetectionServiceTest,SetEnabledAndRefreshState)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