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