safe_browsing_database_unittest.cc revision c407dc5cd9bdc5668497f21b26b09d988ab439de
1// Copyright (c) 2010 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// Unit tests for the SafeBrowsing storage system. 6 7#include "base/file_util.h" 8#include "base/format_macros.h" 9#include "base/logging.h" 10#include "base/path_service.h" 11#include "base/process_util.h" 12#include "base/sha2.h" 13#include "base/stats_counters.h" 14#include "base/string_util.h" 15#include "base/time.h" 16#include "chrome/browser/safe_browsing/protocol_parser.h" 17#include "chrome/browser/safe_browsing/safe_browsing_database.h" 18#include "chrome/browser/safe_browsing/safe_browsing_store_unittest_helper.h" 19#include "chrome/test/file_test_utils.h" 20#include "googleurl/src/gurl.h" 21#include "testing/gtest/include/gtest/gtest.h" 22#include "testing/platform_test.h" 23 24using base::Time; 25 26static const FilePath::CharType kBloomSuffix[] = FILE_PATH_LITERAL(" Bloom"); 27static const FilePath::CharType kFolderPrefix[] = 28 FILE_PATH_LITERAL("SafeBrowsingTestDatabase"); 29 30namespace { 31 32SBPrefix Sha256Prefix(const std::string& str) { 33 SBPrefix prefix; 34 base::SHA256HashString(str, &prefix, sizeof(prefix)); 35 return prefix; 36} 37 38SBFullHash Sha256Hash(const std::string& str) { 39 SBFullHash hash; 40 base::SHA256HashString(str, &hash, sizeof(hash)); 41 return hash; 42} 43 44} // namespace 45 46class SafeBrowsingDatabaseTest : public PlatformTest { 47 public: 48 virtual void SetUp() { 49 PlatformTest::SetUp(); 50 51 // Temporary directory for the database files. 52 FilePath temp_dir; 53 ASSERT_TRUE(file_util::CreateNewTempDirectory(kFolderPrefix, &temp_dir)); 54 file_deleter_.reset(new FileAutoDeleter(temp_dir)); 55 56 FilePath filename(temp_dir); 57 filename = filename.AppendASCII("SafeBrowsingTestDatabase"); 58 59 // In case it existed from a previous run. 60 file_util::Delete(FilePath(filename.value() + kBloomSuffix), false); 61 file_util::Delete(filename, false); 62 63 database_.reset(SafeBrowsingDatabase::Create()); 64 database_->Init(filename); 65 } 66 67 virtual void TearDown() { 68 database_.reset(); 69 file_deleter_.reset(); 70 71 PlatformTest::TearDown(); 72 } 73 74 void GetListsInfo(std::vector<SBListChunkRanges>* lists) { 75 EXPECT_TRUE(database_->UpdateStarted()); 76 database_->GetListsInfo(lists); 77 database_->UpdateFinished(true); 78 } 79 80 // Helper function to do an AddDel or SubDel command. 81 void DelChunk(const std::string& list, 82 int chunk_id, 83 bool is_sub_del) { 84 std::vector<SBChunkDelete> deletes; 85 SBChunkDelete chunk_delete; 86 chunk_delete.list_name = list; 87 chunk_delete.is_sub_del = is_sub_del; 88 chunk_delete.chunk_del.push_back(ChunkRange(chunk_id)); 89 deletes.push_back(chunk_delete); 90 database_->DeleteChunks(deletes); 91 } 92 93 void AddDelChunk(const std::string& list, int chunk_id) { 94 DelChunk(list, chunk_id, false); 95 } 96 97 void SubDelChunk(const std::string& list, int chunk_id) { 98 DelChunk(list, chunk_id, true); 99 } 100 101 // Utility function for setting up the database for the caching test. 102 void PopulateDatabaseForCacheTest(); 103 104 scoped_ptr<FileAutoDeleter> file_deleter_; 105 scoped_ptr<SafeBrowsingDatabase> database_; 106}; 107 108// Tests retrieving list name information. 109TEST_F(SafeBrowsingDatabaseTest, ListName) { 110 SBChunkList chunks; 111 112 // Insert some malware add chunks. 113 SBChunkHost host; 114 host.host = Sha256Prefix("www.evil.com/"); 115 host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 1); 116 host.entry->set_chunk_id(1); 117 host.entry->SetPrefixAt(0, Sha256Prefix("www.evil.com/malware.html")); 118 SBChunk chunk; 119 chunk.chunk_number = 1; 120 chunk.is_add = true; 121 chunk.hosts.push_back(host); 122 chunks.clear(); 123 chunks.push_back(chunk); 124 database_->UpdateStarted(); 125 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 126 127 host.host = Sha256Prefix("www.foo.com/"); 128 host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 1); 129 host.entry->set_chunk_id(2); 130 host.entry->SetPrefixAt(0, Sha256Prefix("www.foo.com/malware.html")); 131 chunk.chunk_number = 2; 132 chunk.is_add = true; 133 chunk.hosts.clear(); 134 chunk.hosts.push_back(host); 135 chunks.clear(); 136 chunks.push_back(chunk); 137 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 138 139 host.host = Sha256Prefix("www.whatever.com/"); 140 host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 1); 141 host.entry->set_chunk_id(3); 142 host.entry->SetPrefixAt(0, Sha256Prefix("www.whatever.com/malware.html")); 143 chunk.chunk_number = 3; 144 chunk.is_add = true; 145 chunk.hosts.clear(); 146 chunk.hosts.push_back(host); 147 chunks.clear(); 148 chunks.push_back(chunk); 149 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 150 database_->UpdateFinished(true); 151 152 std::vector<SBListChunkRanges> lists; 153 GetListsInfo(&lists); 154 EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList); 155 EXPECT_EQ(lists[0].adds, "1-3"); 156 EXPECT_TRUE(lists[0].subs.empty()); 157 lists.clear(); 158 159 // Insert a malware sub chunk. 160 host.host = Sha256Prefix("www.subbed.com/"); 161 host.entry = SBEntry::Create(SBEntry::SUB_PREFIX, 1); 162 host.entry->set_chunk_id(7); 163 host.entry->SetChunkIdAtPrefix(0, 19); 164 host.entry->SetPrefixAt(0, Sha256Prefix("www.subbed.com/notevil1.html")); 165 chunk.chunk_number = 7; 166 chunk.is_add = false; 167 chunk.hosts.clear(); 168 chunk.hosts.push_back(host); 169 chunks.clear(); 170 chunks.push_back(chunk); 171 172 database_->UpdateStarted(); 173 database_->GetListsInfo(&lists); 174 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 175 database_->UpdateFinished(true); 176 lists.clear(); 177 178 GetListsInfo(&lists); 179 EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList); 180 EXPECT_EQ(lists[0].adds, "1-3"); 181 EXPECT_EQ(lists[0].subs, "7"); 182 if (lists.size() == 2) { 183 // Old style database won't have the second entry since it creates the lists 184 // when it receives an update containing that list. The new bloom filter 185 // based database has these values hard coded. 186 EXPECT_TRUE(lists[1].name == safe_browsing_util::kPhishingList); 187 EXPECT_TRUE(lists[1].adds.empty()); 188 EXPECT_TRUE(lists[1].subs.empty()); 189 } 190 lists.clear(); 191 192 // Add a phishing add chunk. 193 host.host = Sha256Prefix("www.evil.com/"); 194 host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 1); 195 host.entry->set_chunk_id(47); 196 host.entry->SetPrefixAt(0, Sha256Prefix("www.evil.com/phishing.html")); 197 chunk.chunk_number = 47; 198 chunk.is_add = true; 199 chunk.hosts.clear(); 200 chunk.hosts.push_back(host); 201 chunks.clear(); 202 chunks.push_back(chunk); 203 database_->UpdateStarted(); 204 database_->GetListsInfo(&lists); 205 database_->InsertChunks(safe_browsing_util::kPhishingList, chunks); 206 207 // Insert some phishing sub chunks. 208 host.host = Sha256Prefix("www.phishy.com/"); 209 host.entry = SBEntry::Create(SBEntry::SUB_PREFIX, 1); 210 host.entry->set_chunk_id(200); 211 host.entry->SetChunkIdAtPrefix(0, 1999); 212 host.entry->SetPrefixAt(0, Sha256Prefix("www.phishy.com/notevil1.html")); 213 chunk.chunk_number = 200; 214 chunk.is_add = false; 215 chunk.hosts.clear(); 216 chunk.hosts.push_back(host); 217 chunks.clear(); 218 chunks.push_back(chunk); 219 database_->InsertChunks(safe_browsing_util::kPhishingList, chunks); 220 221 host.host = Sha256Prefix("www.phishy2.com/"); 222 host.entry = SBEntry::Create(SBEntry::SUB_PREFIX, 1); 223 host.entry->set_chunk_id(201); 224 host.entry->SetChunkIdAtPrefix(0, 1999); 225 host.entry->SetPrefixAt(0, Sha256Prefix("www.phishy2.com/notevil1.html")); 226 chunk.chunk_number = 201; 227 chunk.is_add = false; 228 chunk.hosts.clear(); 229 chunk.hosts.push_back(host); 230 chunks.clear(); 231 chunks.push_back(chunk); 232 database_->InsertChunks(safe_browsing_util::kPhishingList, chunks); 233 database_->UpdateFinished(true); 234 lists.clear(); 235 236 GetListsInfo(&lists); 237 EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList); 238 EXPECT_EQ(lists[0].adds, "1-3"); 239 EXPECT_EQ(lists[0].subs, "7"); 240 EXPECT_TRUE(lists[1].name == safe_browsing_util::kPhishingList); 241 EXPECT_EQ(lists[1].adds, "47"); 242 EXPECT_EQ(lists[1].subs, "200-201"); 243 lists.clear(); 244} 245 246// Checks database reading and writing. 247TEST_F(SafeBrowsingDatabaseTest, Database) { 248 SBChunkList chunks; 249 250 // Add a simple chunk with one hostkey. 251 SBChunkHost host; 252 host.host = Sha256Prefix("www.evil.com/"); 253 host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 2); 254 host.entry->set_chunk_id(1); 255 host.entry->SetPrefixAt(0, Sha256Prefix("www.evil.com/phishing.html")); 256 host.entry->SetPrefixAt(1, Sha256Prefix("www.evil.com/malware.html")); 257 258 SBChunk chunk; 259 chunk.chunk_number = 1; 260 chunk.is_add = true; 261 chunk.hosts.push_back(host); 262 263 chunks.clear(); 264 chunks.push_back(chunk); 265 std::vector<SBListChunkRanges> lists; 266 database_->UpdateStarted(); 267 database_->GetListsInfo(&lists); 268 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 269 270 // Add another chunk with two different hostkeys. 271 host.host = Sha256Prefix("www.evil.com/"); 272 host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 2); 273 host.entry->set_chunk_id(2); 274 host.entry->SetPrefixAt(0, Sha256Prefix("www.evil.com/notevil1.html")); 275 host.entry->SetPrefixAt(1, Sha256Prefix("www.evil.com/notevil2.html")); 276 277 chunk.chunk_number = 2; 278 chunk.hosts.clear(); 279 chunk.hosts.push_back(host); 280 281 host.host = Sha256Prefix("www.good.com/"); 282 host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 2); 283 host.entry->set_chunk_id(2); 284 host.entry->SetPrefixAt(0, Sha256Prefix("www.good.com/good1.html")); 285 host.entry->SetPrefixAt(1, Sha256Prefix("www.good.com/good2.html")); 286 287 chunk.hosts.push_back(host); 288 289 chunks.clear(); 290 chunks.push_back(chunk); 291 292 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 293 294 // and a chunk with an IP-based host 295 host.host = Sha256Prefix("192.168.0.1/"); 296 host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 1); 297 host.entry->set_chunk_id(3); 298 host.entry->SetPrefixAt(0, Sha256Prefix("192.168.0.1/malware.html")); 299 300 chunk.chunk_number = 3; 301 chunk.hosts.clear(); 302 chunk.hosts.push_back(host); 303 304 chunks.clear(); 305 chunks.push_back(chunk); 306 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 307 database_->UpdateFinished(true); 308 lists.clear(); 309 310 // Make sure they were added correctly. 311 GetListsInfo(&lists); 312 EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList); 313 EXPECT_EQ(lists[0].adds, "1-3"); 314 EXPECT_TRUE(lists[0].subs.empty()); 315 lists.clear(); 316 317 const Time now = Time::Now(); 318 std::vector<SBFullHashResult> full_hashes; 319 std::vector<SBPrefix> prefix_hits; 320 std::string matching_list; 321 EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.evil.com/phishing.html"), 322 &matching_list, &prefix_hits, 323 &full_hashes, now)); 324 EXPECT_EQ(prefix_hits[0], Sha256Prefix("www.evil.com/phishing.html")); 325 EXPECT_EQ(prefix_hits.size(), 1U); 326 327 EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.evil.com/malware.html"), 328 &matching_list, &prefix_hits, 329 &full_hashes, now)); 330 331 EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.evil.com/notevil1.html"), 332 &matching_list, &prefix_hits, 333 &full_hashes, now)); 334 335 EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.evil.com/notevil2.html"), 336 &matching_list, &prefix_hits, 337 &full_hashes, now)); 338 339 EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.good.com/good1.html"), 340 &matching_list, &prefix_hits, 341 &full_hashes, now)); 342 343 EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.good.com/good2.html"), 344 &matching_list, &prefix_hits, 345 &full_hashes, now)); 346 347 EXPECT_TRUE(database_->ContainsUrl(GURL("http://192.168.0.1/malware.html"), 348 &matching_list, &prefix_hits, 349 &full_hashes, now)); 350 351 EXPECT_FALSE(database_->ContainsUrl(GURL("http://www.evil.com/"), 352 &matching_list, &prefix_hits, 353 &full_hashes, now)); 354 EXPECT_EQ(prefix_hits.size(), 0U); 355 356 EXPECT_FALSE(database_->ContainsUrl(GURL("http://www.evil.com/robots.txt"), 357 &matching_list, &prefix_hits, 358 &full_hashes, now)); 359 360 361 362 // Attempt to re-add the first chunk (should be a no-op). 363 // see bug: http://code.google.com/p/chromium/issues/detail?id=4522 364 host.host = Sha256Prefix("www.evil.com/"); 365 host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 2); 366 host.entry->set_chunk_id(1); 367 host.entry->SetPrefixAt(0, Sha256Prefix("www.evil.com/phishing.html")); 368 host.entry->SetPrefixAt(1, Sha256Prefix("www.evil.com/malware.html")); 369 370 chunk.chunk_number = 1; 371 chunk.is_add = true; 372 chunk.hosts.clear(); 373 chunk.hosts.push_back(host); 374 375 chunks.clear(); 376 chunks.push_back(chunk); 377 database_->UpdateStarted(); 378 database_->GetListsInfo(&lists); 379 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 380 database_->UpdateFinished(true); 381 lists.clear(); 382 383 GetListsInfo(&lists); 384 EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList); 385 EXPECT_EQ(lists[0].adds, "1-3"); 386 EXPECT_TRUE(lists[0].subs.empty()); 387 lists.clear(); 388 389 390 // Test removing a single prefix from the add chunk. 391 host.host = Sha256Prefix("www.evil.com/"); 392 host.entry = SBEntry::Create(SBEntry::SUB_PREFIX, 1); 393 host.entry->set_chunk_id(2); 394 host.entry->SetChunkIdAtPrefix(0, 2); 395 host.entry->SetPrefixAt(0, Sha256Prefix("www.evil.com/notevil1.html")); 396 397 chunk.is_add = false; 398 chunk.chunk_number = 4; 399 chunk.hosts.clear(); 400 chunk.hosts.push_back(host); 401 402 chunks.clear(); 403 chunks.push_back(chunk); 404 405 database_->UpdateStarted(); 406 database_->GetListsInfo(&lists); 407 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 408 database_->UpdateFinished(true); 409 lists.clear(); 410 411 EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.evil.com/phishing.html"), 412 &matching_list, &prefix_hits, 413 &full_hashes, now)); 414 EXPECT_EQ(prefix_hits[0], Sha256Prefix("www.evil.com/phishing.html")); 415 EXPECT_EQ(prefix_hits.size(), 1U); 416 417 EXPECT_FALSE(database_->ContainsUrl(GURL("http://www.evil.com/notevil1.html"), 418 &matching_list, &prefix_hits, 419 &full_hashes, now)); 420 EXPECT_EQ(prefix_hits.size(), 0U); 421 422 EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.evil.com/notevil2.html"), 423 &matching_list, &prefix_hits, 424 &full_hashes, now)); 425 426 EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.good.com/good1.html"), 427 &matching_list, &prefix_hits, 428 &full_hashes, now)); 429 430 EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.good.com/good2.html"), 431 &matching_list, &prefix_hits, 432 &full_hashes, now)); 433 434 GetListsInfo(&lists); 435 EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList); 436 EXPECT_EQ(lists[0].subs, "4"); 437 lists.clear(); 438 439 // Test the same sub chunk again. This should be a no-op. 440 // see bug: http://code.google.com/p/chromium/issues/detail?id=4522 441 host.host = Sha256Prefix("www.evil.com/"); 442 host.entry = SBEntry::Create(SBEntry::SUB_PREFIX, 1); 443 host.entry->set_chunk_id(2); 444 host.entry->SetChunkIdAtPrefix(0, 2); 445 host.entry->SetPrefixAt(0, Sha256Prefix("www.evil.com/notevil1.html")); 446 447 chunk.is_add = false; 448 chunk.chunk_number = 4; 449 chunk.hosts.clear(); 450 chunk.hosts.push_back(host); 451 452 chunks.clear(); 453 chunks.push_back(chunk); 454 455 database_->UpdateStarted(); 456 database_->GetListsInfo(&lists); 457 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 458 database_->UpdateFinished(true); 459 lists.clear(); 460 461 GetListsInfo(&lists); 462 EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList); 463 EXPECT_EQ(lists[0].subs, "4"); 464 lists.clear(); 465 466 467 // Test removing all the prefixes from an add chunk. 468 database_->UpdateStarted(); 469 database_->GetListsInfo(&lists); 470 AddDelChunk(safe_browsing_util::kMalwareList, 2); 471 database_->UpdateFinished(true); 472 lists.clear(); 473 474 EXPECT_FALSE(database_->ContainsUrl(GURL("http://www.evil.com/notevil2.html"), 475 &matching_list, &prefix_hits, 476 &full_hashes, now)); 477 478 EXPECT_FALSE(database_->ContainsUrl(GURL("http://www.good.com/good1.html"), 479 &matching_list, &prefix_hits, 480 &full_hashes, now)); 481 482 EXPECT_FALSE(database_->ContainsUrl(GURL("http://www.good.com/good2.html"), 483 &matching_list, &prefix_hits, 484 &full_hashes, now)); 485 486 GetListsInfo(&lists); 487 EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList); 488 EXPECT_EQ(lists[0].adds, "1,3"); 489 EXPECT_EQ(lists[0].subs, "4"); 490 lists.clear(); 491 492 // The adddel command exposed a bug in the transaction code where any 493 // transaction after it would fail. Add a dummy entry and remove it to 494 // make sure the transcation works fine. 495 host.host = Sha256Prefix("www.redherring.com/"); 496 host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 1); 497 host.entry->set_chunk_id(1); 498 host.entry->SetPrefixAt(0, Sha256Prefix("www.redherring.com/index.html")); 499 500 chunk.is_add = true; 501 chunk.chunk_number = 44; 502 chunk.hosts.clear(); 503 chunk.hosts.push_back(host); 504 505 chunks.clear(); 506 chunks.push_back(chunk); 507 database_->UpdateStarted(); 508 database_->GetListsInfo(&lists); 509 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 510 511 // Now remove the dummy entry. If there are any problems with the 512 // transactions, asserts will fire. 513 AddDelChunk(safe_browsing_util::kMalwareList, 44); 514 515 // Test the subdel command. 516 SubDelChunk(safe_browsing_util::kMalwareList, 4); 517 database_->UpdateFinished(true); 518 lists.clear(); 519 520 GetListsInfo(&lists); 521 EXPECT_TRUE(lists[0].name == safe_browsing_util::kMalwareList); 522 EXPECT_EQ(lists[0].adds, "1,3"); 523 EXPECT_EQ(lists[0].subs, ""); 524 lists.clear(); 525 526 // Test a sub command coming in before the add. 527 host.host = Sha256Prefix("www.notevilanymore.com/"); 528 host.entry = SBEntry::Create(SBEntry::SUB_PREFIX, 2); 529 host.entry->set_chunk_id(10); 530 host.entry->SetPrefixAt(0, Sha256Prefix("www.notevilanymore.com/index.html")); 531 host.entry->SetChunkIdAtPrefix(0, 10); 532 host.entry->SetPrefixAt(1, Sha256Prefix("www.notevilanymore.com/good.html")); 533 host.entry->SetChunkIdAtPrefix(1, 10); 534 535 chunk.is_add = false; 536 chunk.chunk_number = 5; 537 chunk.hosts.clear(); 538 chunk.hosts.push_back(host); 539 540 chunks.clear(); 541 chunks.push_back(chunk); 542 database_->UpdateStarted(); 543 database_->GetListsInfo(&lists); 544 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 545 database_->UpdateFinished(true); 546 lists.clear(); 547 548 EXPECT_FALSE(database_->ContainsUrl( 549 GURL("http://www.notevilanymore.com/index.html"), 550 &matching_list, &prefix_hits, &full_hashes, now)); 551 552 // Now insert the tardy add chunk. 553 host.host = Sha256Prefix("www.notevilanymore.com/"); 554 host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 2); 555 host.entry->SetPrefixAt(0, Sha256Prefix("www.notevilanymore.com/index.html")); 556 host.entry->SetPrefixAt(1, Sha256Prefix("www.notevilanymore.com/good.html")); 557 558 chunk.is_add = true; 559 chunk.chunk_number = 10; 560 chunk.hosts.clear(); 561 chunk.hosts.push_back(host); 562 563 chunks.clear(); 564 chunks.push_back(chunk); 565 database_->UpdateStarted(); 566 database_->GetListsInfo(&lists); 567 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 568 database_->UpdateFinished(true); 569 lists.clear(); 570 571 EXPECT_FALSE(database_->ContainsUrl( 572 GURL("http://www.notevilanymore.com/index.html"), 573 &matching_list, &prefix_hits, &full_hashes, now)); 574 575 EXPECT_FALSE(database_->ContainsUrl( 576 GURL("http://www.notevilanymore.com/good.html"), 577 &matching_list, &prefix_hits, &full_hashes, now)); 578} 579 580 581// Test adding zero length chunks to the database. 582TEST_F(SafeBrowsingDatabaseTest, ZeroSizeChunk) { 583 SBChunkList chunks; 584 585 // Populate with a couple of normal chunks. 586 SBChunkHost host; 587 host.host = Sha256Prefix("www.test.com/"); 588 host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 2); 589 host.entry->SetPrefixAt(0, Sha256Prefix("www.test.com/test1.html")); 590 host.entry->SetPrefixAt(1, Sha256Prefix("www.test.com/test2.html")); 591 host.entry->set_chunk_id(1); 592 593 SBChunk chunk; 594 chunk.is_add = true; 595 chunk.chunk_number = 1; 596 chunk.hosts.push_back(host); 597 598 chunks.clear(); 599 chunks.push_back(chunk); 600 601 host.host = Sha256Prefix("www.random.com/"); 602 host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 2); 603 host.entry->SetPrefixAt(0, Sha256Prefix("www.random.com/random1.html")); 604 host.entry->SetPrefixAt(1, Sha256Prefix("www.random.com/random2.html")); 605 host.entry->set_chunk_id(10); 606 chunk.chunk_number = 10; 607 chunk.hosts.clear(); 608 chunk.hosts.push_back(host); 609 chunks.push_back(chunk); 610 611 std::vector<SBListChunkRanges> lists; 612 database_->UpdateStarted(); 613 database_->GetListsInfo(&lists); 614 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 615 database_->UpdateFinished(true); 616 lists.clear(); 617 618 // Add an empty ADD and SUB chunk. 619 GetListsInfo(&lists); 620 EXPECT_EQ(lists[0].adds, "1,10"); 621 lists.clear(); 622 623 SBChunk empty_chunk; 624 empty_chunk.chunk_number = 19; 625 empty_chunk.is_add = true; 626 chunks.clear(); 627 chunks.push_back(empty_chunk); 628 database_->UpdateStarted(); 629 database_->GetListsInfo(&lists); 630 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 631 chunks.clear(); 632 empty_chunk.chunk_number = 7; 633 empty_chunk.is_add = false; 634 chunks.push_back(empty_chunk); 635 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 636 database_->UpdateFinished(true); 637 lists.clear(); 638 639 GetListsInfo(&lists); 640 EXPECT_EQ(lists[0].adds, "1,10,19"); 641 EXPECT_EQ(lists[0].subs, "7"); 642 lists.clear(); 643 644 // Add an empty chunk along with a couple that contain data. This should 645 // result in the chunk range being reduced in size. 646 host.host = Sha256Prefix("www.notempty.com/"); 647 host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 1); 648 host.entry->SetPrefixAt(0, Sha256Prefix("www.notempty.com/full1.html")); 649 host.entry->set_chunk_id(20); 650 empty_chunk.chunk_number = 20; 651 empty_chunk.is_add = true; 652 empty_chunk.hosts.clear(); 653 empty_chunk.hosts.push_back(host); 654 chunks.clear(); 655 chunks.push_back(empty_chunk); 656 657 empty_chunk.chunk_number = 21; 658 empty_chunk.is_add = true; 659 empty_chunk.hosts.clear(); 660 chunks.push_back(empty_chunk); 661 662 host.host = Sha256Prefix("www.notempty.com/"); 663 host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 1); 664 host.entry->SetPrefixAt(0, Sha256Prefix("www.notempty.com/full2.html")); 665 host.entry->set_chunk_id(22); 666 empty_chunk.hosts.clear(); 667 empty_chunk.hosts.push_back(host); 668 empty_chunk.chunk_number = 22; 669 empty_chunk.is_add = true; 670 chunks.push_back(empty_chunk); 671 672 database_->UpdateStarted(); 673 database_->GetListsInfo(&lists); 674 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 675 database_->UpdateFinished(true); 676 lists.clear(); 677 678 const Time now = Time::Now(); 679 std::vector<SBFullHashResult> full_hashes; 680 std::vector<SBPrefix> prefix_hits; 681 std::string matching_list; 682 EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.notempty.com/full1.html"), 683 &matching_list, &prefix_hits, 684 &full_hashes, now)); 685 EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.notempty.com/full2.html"), 686 &matching_list, &prefix_hits, 687 &full_hashes, now)); 688 689 GetListsInfo(&lists); 690 EXPECT_EQ(lists[0].adds, "1,10,19-22"); 691 EXPECT_EQ(lists[0].subs, "7"); 692 lists.clear(); 693 694 // Handle AddDel and SubDel commands for empty chunks. 695 database_->UpdateStarted(); 696 database_->GetListsInfo(&lists); 697 AddDelChunk(safe_browsing_util::kMalwareList, 21); 698 database_->UpdateFinished(true); 699 lists.clear(); 700 701 GetListsInfo(&lists); 702 EXPECT_EQ(lists[0].adds, "1,10,19-20,22"); 703 EXPECT_EQ(lists[0].subs, "7"); 704 lists.clear(); 705 706 database_->UpdateStarted(); 707 database_->GetListsInfo(&lists); 708 SubDelChunk(safe_browsing_util::kMalwareList, 7); 709 database_->UpdateFinished(true); 710 lists.clear(); 711 712 GetListsInfo(&lists); 713 EXPECT_EQ(lists[0].adds, "1,10,19-20,22"); 714 EXPECT_EQ(lists[0].subs, ""); 715 lists.clear(); 716} 717 718// Utility function for setting up the database for the caching test. 719void SafeBrowsingDatabaseTest::PopulateDatabaseForCacheTest() { 720 // Add a simple chunk with one hostkey and cache it. 721 SBChunkHost host; 722 host.host = Sha256Prefix("www.evil.com/"); 723 host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 2); 724 host.entry->set_chunk_id(1); 725 host.entry->SetPrefixAt(0, Sha256Prefix("www.evil.com/phishing.html")); 726 host.entry->SetPrefixAt(1, Sha256Prefix("www.evil.com/malware.html")); 727 728 SBChunk chunk; 729 chunk.chunk_number = 1; 730 chunk.is_add = true; 731 chunk.hosts.push_back(host); 732 733 SBChunkList chunks; 734 std::vector<SBListChunkRanges> lists; 735 chunks.push_back(chunk); 736 database_->UpdateStarted(); 737 database_->GetListsInfo(&lists); 738 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 739 database_->UpdateFinished(true); 740 lists.clear(); 741 742 // Add the GetHash results to the cache. 743 SBFullHashResult full_hash; 744 full_hash.hash = Sha256Hash("www.evil.com/phishing.html"); 745 full_hash.list_name = safe_browsing_util::kMalwareList; 746 full_hash.add_chunk_id = 1; 747 748 std::vector<SBFullHashResult> results; 749 results.push_back(full_hash); 750 751 full_hash.hash = Sha256Hash("www.evil.com/malware.html"); 752 results.push_back(full_hash); 753 754 std::vector<SBPrefix> prefixes; 755 database_->CacheHashResults(prefixes, results); 756} 757 758TEST_F(SafeBrowsingDatabaseTest, HashCaching) { 759 PopulateDatabaseForCacheTest(); 760 761 // We should have both full hashes in the cache. 762 SafeBrowsingDatabase::HashCache* hash_cache = database_->hash_cache(); 763 EXPECT_EQ(hash_cache->size(), 2U); 764 765 // Test the cache lookup for the first prefix. 766 std::string listname; 767 std::vector<SBPrefix> prefixes; 768 std::vector<SBFullHashResult> full_hashes; 769 database_->ContainsUrl(GURL("http://www.evil.com/phishing.html"), 770 &listname, &prefixes, &full_hashes, Time::Now()); 771 EXPECT_EQ(full_hashes.size(), 1U); 772 EXPECT_TRUE(SBFullHashEq(full_hashes[0].hash, 773 Sha256Hash("www.evil.com/phishing.html"))); 774 775 prefixes.clear(); 776 full_hashes.clear(); 777 778 // Test the cache lookup for the second prefix. 779 database_->ContainsUrl(GURL("http://www.evil.com/malware.html"), 780 &listname, &prefixes, &full_hashes, Time::Now()); 781 EXPECT_EQ(full_hashes.size(), 1U); 782 EXPECT_TRUE(SBFullHashEq(full_hashes[0].hash, 783 Sha256Hash("www.evil.com/malware.html"))); 784 785 prefixes.clear(); 786 full_hashes.clear(); 787 788 // Test removing a prefix via a sub chunk. 789 SBChunkHost host; 790 host.host = Sha256Prefix("www.evil.com/"); 791 host.entry = SBEntry::Create(SBEntry::SUB_PREFIX, 1); 792 host.entry->set_chunk_id(1); 793 host.entry->SetChunkIdAtPrefix(0, 1); 794 host.entry->SetPrefixAt(0, Sha256Prefix("www.evil.com/phishing.html")); 795 796 SBChunk chunk; 797 chunk.chunk_number = 2; 798 chunk.is_add = false; 799 chunk.hosts.clear(); 800 chunk.hosts.push_back(host); 801 SBChunkList chunks; 802 chunks.push_back(chunk); 803 804 std::vector<SBListChunkRanges> lists; 805 database_->UpdateStarted(); 806 database_->GetListsInfo(&lists); 807 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 808 database_->UpdateFinished(true); 809 lists.clear(); 810 811 // This prefix should still be there. 812 database_->ContainsUrl(GURL("http://www.evil.com/malware.html"), 813 &listname, &prefixes, &full_hashes, Time::Now()); 814 EXPECT_EQ(full_hashes.size(), 1U); 815 EXPECT_TRUE(SBFullHashEq(full_hashes[0].hash, 816 Sha256Hash("www.evil.com/malware.html"))); 817 818 prefixes.clear(); 819 full_hashes.clear(); 820 821 // This prefix should be gone. 822 database_->ContainsUrl(GURL("http://www.evil.com/phishing.html"), 823 &listname, &prefixes, &full_hashes, Time::Now()); 824 EXPECT_EQ(full_hashes.size(), 0U); 825 826 prefixes.clear(); 827 full_hashes.clear(); 828 829 // Test that an AddDel for the original chunk removes the last cached entry. 830 database_->UpdateStarted(); 831 database_->GetListsInfo(&lists); 832 AddDelChunk(safe_browsing_util::kMalwareList, 1); 833 database_->UpdateFinished(true); 834 database_->ContainsUrl(GURL("http://www.evil.com/malware.html"), 835 &listname, &prefixes, &full_hashes, Time::Now()); 836 EXPECT_EQ(full_hashes.size(), 0U); 837 EXPECT_EQ(database_->hash_cache()->size(), 0U); 838 839 lists.clear(); 840 prefixes.clear(); 841 full_hashes.clear(); 842 843 // Test that the cache won't return expired values. First we have to adjust 844 // the cached entries' received time to make them older, since the database 845 // cache insert uses Time::Now(). First, store some entries. 846 PopulateDatabaseForCacheTest(); 847 hash_cache = database_->hash_cache(); 848 EXPECT_EQ(hash_cache->size(), 2U); 849 850 // Now adjust one of the entries times to be in the past. 851 base::Time expired = base::Time::Now() - base::TimeDelta::FromMinutes(60); 852 const SBPrefix key = Sha256Prefix("www.evil.com/malware.html"); 853 SafeBrowsingDatabase::HashList& entries = (*hash_cache)[key]; 854 SafeBrowsingDatabase::HashCacheEntry entry = entries.front(); 855 entries.pop_front(); 856 entry.received = expired; 857 entries.push_back(entry); 858 859 database_->ContainsUrl(GURL("http://www.evil.com/malware.html"), 860 &listname, &prefixes, &full_hashes, expired); 861 EXPECT_EQ(full_hashes.size(), 0U); 862 863 // This entry should still exist. 864 database_->ContainsUrl(GURL("http://www.evil.com/phishing.html"), 865 &listname, &prefixes, &full_hashes, expired); 866 EXPECT_EQ(full_hashes.size(), 1U); 867 868 869 // Testing prefix miss caching. First, we clear out the existing database, 870 // Since PopulateDatabaseForCacheTest() doesn't handle adding duplicate 871 // chunks. 872 database_->UpdateStarted(); 873 database_->GetListsInfo(&lists); 874 AddDelChunk(safe_browsing_util::kMalwareList, 1); 875 database_->UpdateFinished(true); 876 lists.clear(); 877 878 std::vector<SBPrefix> prefix_misses; 879 std::vector<SBFullHashResult> empty_full_hash; 880 prefix_misses.push_back(Sha256Prefix("http://www.bad.com/malware.html")); 881 prefix_misses.push_back(Sha256Prefix("http://www.bad.com/phishing.html")); 882 database_->CacheHashResults(prefix_misses, empty_full_hash); 883 884 // Prefixes with no full results are misses. 885 EXPECT_EQ(database_->prefix_miss_cache()->size(), 2U); 886 887 // Update the database. 888 PopulateDatabaseForCacheTest(); 889 890 // Prefix miss cache should be cleared. 891 EXPECT_EQ(database_->prefix_miss_cache()->size(), 0U); 892 893 // Cache a GetHash miss for a particular prefix, and even though the prefix is 894 // in the database, it is flagged as a miss so looking up the associated URL 895 // will not succeed. 896 prefixes.clear(); 897 full_hashes.clear(); 898 prefix_misses.clear(); 899 empty_full_hash.clear(); 900 prefix_misses.push_back(Sha256Prefix("www.evil.com/phishing.html")); 901 database_->CacheHashResults(prefix_misses, empty_full_hash); 902 EXPECT_FALSE(database_->ContainsUrl(GURL("http://www.evil.com/phishing.html"), 903 &listname, &prefixes, 904 &full_hashes, Time::Now())); 905 906 lists.clear(); 907 prefixes.clear(); 908 full_hashes.clear(); 909 910 // Test receiving a full add chunk. 911 host.host = Sha256Prefix("www.fullevil.com/"); 912 host.entry = SBEntry::Create(SBEntry::ADD_FULL_HASH, 2); 913 host.entry->set_chunk_id(20); 914 host.entry->SetFullHashAt(0, Sha256Hash("www.fullevil.com/bad1.html")); 915 host.entry->SetFullHashAt(1, Sha256Hash("www.fullevil.com/bad2.html")); 916 917 chunk.chunk_number = 20; 918 chunk.is_add = true; 919 chunk.hosts.clear(); 920 chunk.hosts.push_back(host); 921 chunks.clear(); 922 chunks.push_back(chunk); 923 database_->UpdateStarted(); 924 database_->GetListsInfo(&lists); 925 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 926 database_->UpdateFinished(true); 927 928 EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.fullevil.com/bad1.html"), 929 &listname, &prefixes, &full_hashes, 930 Time::Now())); 931 EXPECT_EQ(full_hashes.size(), 1U); 932 EXPECT_TRUE(SBFullHashEq(full_hashes[0].hash, 933 Sha256Hash("www.fullevil.com/bad1.html"))); 934 lists.clear(); 935 prefixes.clear(); 936 full_hashes.clear(); 937 938 EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.fullevil.com/bad2.html"), 939 &listname, &prefixes, &full_hashes, 940 Time::Now())); 941 EXPECT_EQ(full_hashes.size(), 1U); 942 EXPECT_TRUE(SBFullHashEq(full_hashes[0].hash, 943 Sha256Hash("www.fullevil.com/bad2.html"))); 944 lists.clear(); 945 prefixes.clear(); 946 full_hashes.clear(); 947 948 // Test receiving a full sub chunk, which will remove one of the full adds. 949 host.host = Sha256Prefix("www.fullevil.com/"); 950 host.entry = SBEntry::Create(SBEntry::SUB_FULL_HASH, 1); 951 host.entry->set_chunk_id(200); 952 host.entry->SetChunkIdAtPrefix(0, 20); 953 host.entry->SetFullHashAt(0, Sha256Hash("www.fullevil.com/bad1.html")); 954 955 chunk.chunk_number = 200; 956 chunk.is_add = false; 957 chunk.hosts.clear(); 958 chunk.hosts.push_back(host); 959 chunks.clear(); 960 chunks.push_back(chunk); 961 database_->UpdateStarted(); 962 database_->GetListsInfo(&lists); 963 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); 964 database_->UpdateFinished(true); 965 966 EXPECT_FALSE(database_->ContainsUrl(GURL("http://www.fullevil.com/bad1.html"), 967 &listname, &prefixes, &full_hashes, 968 Time::Now())); 969 EXPECT_EQ(full_hashes.size(), 0U); 970 971 // There should be one remaining full add. 972 EXPECT_TRUE(database_->ContainsUrl(GURL("http://www.fullevil.com/bad2.html"), 973 &listname, &prefixes, &full_hashes, 974 Time::Now())); 975 EXPECT_EQ(full_hashes.size(), 1U); 976 EXPECT_TRUE(SBFullHashEq(full_hashes[0].hash, 977 Sha256Hash("www.fullevil.com/bad2.html"))); 978 lists.clear(); 979 prefixes.clear(); 980 full_hashes.clear(); 981 982 // Now test an AddDel for the remaining full add. 983 database_->UpdateStarted(); 984 database_->GetListsInfo(&lists); 985 AddDelChunk(safe_browsing_util::kMalwareList, 20); 986 database_->UpdateFinished(true); 987 lists.clear(); 988 989 EXPECT_FALSE(database_->ContainsUrl(GURL("http://www.fullevil.com/bad1.html"), 990 &listname, &prefixes, &full_hashes, 991 Time::Now())); 992 EXPECT_FALSE(database_->ContainsUrl(GURL("http://www.fullevil.com/bad2.html"), 993 &listname, &prefixes, &full_hashes, 994 Time::Now())); 995} 996 997namespace { 998 999void PrintStat(const char* name) { 1000 int value = StatsTable::current()->GetCounterValue(name); 1001 LOG(INFO) << StringPrintf("%s %d", name, value); 1002} 1003 1004FilePath GetFullSBDataPath(const FilePath& path) { 1005 FilePath full_path; 1006 CHECK(PathService::Get(base::DIR_SOURCE_ROOT, &full_path)); 1007 full_path = full_path.AppendASCII("chrome"); 1008 full_path = full_path.AppendASCII("test"); 1009 full_path = full_path.AppendASCII("data"); 1010 full_path = full_path.AppendASCII("safe_browsing"); 1011 full_path = full_path.Append(path); 1012 CHECK(file_util::PathExists(full_path)); 1013 return full_path; 1014} 1015 1016// TODO(shess): The clients of this structure manually manage 1017// |chunks|. Improve this code to apply the RAII idiom to manage 1018// |chunks|. 1019struct ChunksInfo { 1020 SBChunkList* chunks; // weak 1021 std::string listname; 1022}; 1023 1024void PerformUpdate(const FilePath& initial_db, 1025 const std::vector<ChunksInfo>& chunks, 1026 const std::vector<SBChunkDelete>& deletes) { 1027 base::IoCounters before, after; 1028 1029 FilePath path; 1030 PathService::Get(base::DIR_TEMP, &path); 1031 path = path.AppendASCII("SafeBrowsingTestDatabase"); 1032 1033 // In case it existed from a previous run. 1034 file_util::Delete(path, false); 1035 1036 if (!initial_db.empty()) { 1037 FilePath full_initial_db = GetFullSBDataPath(initial_db); 1038 ASSERT_TRUE(file_util::CopyFile(full_initial_db, path)); 1039 } 1040 1041 SafeBrowsingDatabase* database = SafeBrowsingDatabase::Create(); 1042 database->Init(path); 1043 1044 Time before_time = Time::Now(); 1045 base::ProcessHandle handle = base::Process::Current().handle(); 1046 scoped_ptr<base::ProcessMetrics> metric( 1047#if !defined(OS_MACOSX) 1048 base::ProcessMetrics::CreateProcessMetrics(handle)); 1049#else 1050 // Getting stats only for the current process is enough, so NULL is fine. 1051 base::ProcessMetrics::CreateProcessMetrics(handle, NULL)); 1052#endif 1053 // Get IO stats. These are currently not supported on Mac, and may not be 1054 // available for Linux, so we check the result and only show IO stats if 1055 // they are available. 1056 bool gotIOCounters = metric->GetIOCounters(&before); 1057 1058 std::vector<SBListChunkRanges> lists; 1059 database->UpdateStarted(); 1060 database->GetListsInfo(&lists); 1061 database->DeleteChunks(deletes); 1062 for (size_t i = 0; i < chunks.size(); ++i) 1063 database->InsertChunks(chunks[i].listname, *chunks[i].chunks); 1064 1065 database->UpdateFinished(true); 1066 lists.clear(); 1067 1068 gotIOCounters = gotIOCounters && metric->GetIOCounters(&after); 1069 1070 if (gotIOCounters) { 1071 LOG(INFO) << StringPrintf("I/O Read Bytes: %" PRIu64, 1072 after.ReadTransferCount - before.ReadTransferCount); 1073 LOG(INFO) << StringPrintf("I/O Write Bytes: %" PRIu64, 1074 after.WriteTransferCount - before.WriteTransferCount); 1075 LOG(INFO) << StringPrintf("I/O Reads: %" PRIu64, 1076 after.ReadOperationCount - before.ReadOperationCount); 1077 LOG(INFO) << StringPrintf("I/O Writes: %" PRIu64, 1078 after.WriteOperationCount - before.WriteOperationCount); 1079 } 1080 LOG(INFO) << StringPrintf("Finished in %" PRId64 " ms", 1081 (Time::Now() - before_time).InMilliseconds()); 1082 1083 PrintStat("c:SB.HostSelect"); 1084 PrintStat("c:SB.HostSelectForBloomFilter"); 1085 PrintStat("c:SB.HostReplace"); 1086 PrintStat("c:SB.HostInsert"); 1087 PrintStat("c:SB.HostDelete"); 1088 PrintStat("c:SB.ChunkSelect"); 1089 PrintStat("c:SB.ChunkInsert"); 1090 PrintStat("c:SB.ChunkDelete"); 1091 PrintStat("c:SB.TransactionCommit"); 1092 1093 delete database; 1094} 1095 1096void UpdateDatabase(const FilePath& initial_db, 1097 const FilePath& response_path, 1098 const FilePath& updates_path) { 1099 // First we read the chunks from disk, so that this isn't counted in IO bytes. 1100 std::vector<ChunksInfo> chunks; 1101 1102 SafeBrowsingProtocolParser parser; 1103 if (!updates_path.empty()) { 1104 FilePath data_dir = GetFullSBDataPath(updates_path); 1105 file_util::FileEnumerator file_enum(data_dir, false, 1106 file_util::FileEnumerator::FILES); 1107 while (true) { 1108 FilePath file = file_enum.Next(); 1109 if (file.empty()) 1110 break; 1111 1112 int64 size64; 1113 bool result = file_util::GetFileSize(file, &size64); 1114 CHECK(result); 1115 1116 int size = static_cast<int>(size64); 1117 scoped_array<char> data(new char[size]); 1118 file_util::ReadFile(file, data.get(), size); 1119 1120 ChunksInfo info; 1121 info.chunks = new SBChunkList; 1122 1123 bool re_key; 1124 result = parser.ParseChunk(data.get(), size, "", "", 1125 &re_key, info.chunks); 1126 CHECK(result); 1127 1128 info.listname = WideToASCII(file.BaseName().ToWStringHack()); 1129 size_t index = info.listname.find('_'); // Get rid fo the _s or _a. 1130 info.listname.resize(index); 1131 info.listname.erase(0, 3); // Get rid of the 000 etc. 1132 1133 chunks.push_back(info); 1134 } 1135 } 1136 1137 std::vector<SBChunkDelete> deletes; 1138 if (!response_path.empty()) { 1139 std::string update; 1140 FilePath full_response_path = GetFullSBDataPath(response_path); 1141 if (file_util::ReadFileToString(full_response_path, &update)) { 1142 int next_update; 1143 bool result, rekey, reset; 1144 std::vector<ChunkUrl> urls; 1145 result = parser.ParseUpdate(update.c_str(), 1146 static_cast<int>(update.length()), 1147 "", 1148 &next_update, 1149 &rekey, 1150 &reset, 1151 &deletes, 1152 &urls); 1153 DCHECK(result); 1154 if (!updates_path.empty()) 1155 DCHECK(urls.size() == chunks.size()); 1156 } 1157 } 1158 1159 PerformUpdate(initial_db, chunks, deletes); 1160 1161 // TODO(shess): Make ChunksInfo handle this via scoping. 1162 for (std::vector<ChunksInfo>::iterator iter = chunks.begin(); 1163 iter != chunks.end(); ++iter) { 1164 delete iter->chunks; 1165 iter->chunks = NULL; 1166 } 1167} 1168 1169// Construct the shared base path used by the GetOld* functions. 1170FilePath BasePath() { 1171 return FilePath(FILE_PATH_LITERAL("old")); 1172} 1173 1174FilePath GetOldSafeBrowsingPath() { 1175 return BasePath().AppendASCII("SafeBrowsing"); 1176} 1177 1178FilePath GetOldResponsePath() { 1179 return BasePath().AppendASCII("response"); 1180} 1181 1182FilePath GetOldUpdatesPath() { 1183 return BasePath().AppendASCII("updates"); 1184} 1185 1186} // namespace 1187 1188// Counts the IO needed for the initial update of a database. 1189// test\data\safe_browsing\download_update.py was used to fetch the add/sub 1190// chunks that are read, in order to get repeatable runs. 1191TEST(SafeBrowsingDatabase, DatabaseInitialIO) { 1192 UpdateDatabase(FilePath(), FilePath(), FilePath().AppendASCII("initial")); 1193} 1194 1195// Counts the IO needed to update a month old database. 1196// The data files were generated by running "..\download_update.py postdata" 1197// in the "safe_browsing\old" directory. 1198TEST(SafeBrowsingDatabase, DatabaseOldIO) { 1199 UpdateDatabase(GetOldSafeBrowsingPath(), GetOldResponsePath(), 1200 GetOldUpdatesPath()); 1201} 1202 1203// Like DatabaseOldIO but only the deletes. 1204TEST(SafeBrowsingDatabase, DatabaseOldDeletesIO) { 1205 UpdateDatabase(GetOldSafeBrowsingPath(), GetOldResponsePath(), FilePath()); 1206} 1207 1208// Like DatabaseOldIO but only the updates. 1209TEST(SafeBrowsingDatabase, DatabaseOldUpdatesIO) { 1210 UpdateDatabase(GetOldSafeBrowsingPath(), FilePath(), GetOldUpdatesPath()); 1211} 1212 1213// Does a a lot of addel's on very large chunks. 1214TEST(SafeBrowsingDatabase, DatabaseOldLotsofDeletesIO) { 1215 std::vector<ChunksInfo> chunks; 1216 std::vector<SBChunkDelete> deletes; 1217 SBChunkDelete del; 1218 del.is_sub_del = false; 1219 del.list_name = safe_browsing_util::kMalwareList; 1220 del.chunk_del.push_back(ChunkRange(3539, 3579)); 1221 deletes.push_back(del); 1222 PerformUpdate(GetOldSafeBrowsingPath(), chunks, deletes); 1223} 1224