Home | History | Annotate | Download | only in safe_browsing
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 //
      5 // Unit tests for the SafeBrowsing storage system.
      6 
      7 #include "base/file_util.h"
      8 #include "base/files/scoped_temp_dir.h"
      9 #include "base/logging.h"
     10 #include "base/memory/scoped_vector.h"
     11 #include "base/message_loop/message_loop.h"
     12 #include "base/sha1.h"
     13 #include "base/strings/string_number_conversions.h"
     14 #include "base/strings/string_split.h"
     15 #include "base/time/time.h"
     16 #include "chrome/browser/safe_browsing/chunk.pb.h"
     17 #include "chrome/browser/safe_browsing/safe_browsing_database.h"
     18 #include "chrome/browser/safe_browsing/safe_browsing_store_file.h"
     19 #include "content/public/test/test_browser_thread_bundle.h"
     20 #include "crypto/sha2.h"
     21 #include "net/base/net_util.h"
     22 #include "sql/connection.h"
     23 #include "sql/statement.h"
     24 #include "testing/gtest/include/gtest/gtest.h"
     25 #include "testing/platform_test.h"
     26 #include "url/gurl.h"
     27 
     28 using base::Time;
     29 using base::TimeDelta;
     30 
     31 namespace {
     32 
     33 const TimeDelta kCacheLifetime = TimeDelta::FromMinutes(45);
     34 
     35 SBPrefix SBPrefixForString(const std::string& str) {
     36   return SBFullHashForString(str).prefix;
     37 }
     38 
     39 std::string HashedIpPrefix(const std::string& ip_prefix, size_t prefix_size) {
     40   net::IPAddressNumber ip_number;
     41   EXPECT_TRUE(net::ParseIPLiteralToNumber(ip_prefix, &ip_number));
     42   EXPECT_EQ(net::kIPv6AddressSize, ip_number.size());
     43   const std::string hashed_ip_prefix = base::SHA1HashString(
     44       net::IPAddressToPackedString(ip_number));
     45   std::string hash(crypto::kSHA256Length, '\0');
     46   hash.replace(0, hashed_ip_prefix.size(), hashed_ip_prefix);
     47   hash[base::kSHA1Length] = static_cast<char>(prefix_size);
     48   return hash;
     49 }
     50 
     51 // Helper to build a chunk.  Caller takes ownership.
     52 SBChunkData* BuildChunk(int chunk_number,
     53                         safe_browsing::ChunkData::ChunkType chunk_type,
     54                         safe_browsing::ChunkData::PrefixType prefix_type,
     55                         const void* data, size_t data_size,
     56                         const std::vector<int>& add_chunk_numbers) {
     57   scoped_ptr<safe_browsing::ChunkData> raw_data(new safe_browsing::ChunkData);
     58   raw_data->set_chunk_number(chunk_number);
     59   raw_data->set_chunk_type(chunk_type);
     60   raw_data->set_prefix_type(prefix_type);
     61   raw_data->set_hashes(data, data_size);
     62   raw_data->clear_add_numbers();
     63   for (size_t i = 0; i < add_chunk_numbers.size(); ++i) {
     64     raw_data->add_add_numbers(add_chunk_numbers[i]);
     65   }
     66 
     67   return new SBChunkData(raw_data.release());
     68 }
     69 
     70 // Create add chunk with a single prefix generated from |value|.
     71 SBChunkData* AddChunkPrefixValue(int chunk_number,
     72                                  const std::string& value) {
     73   const SBPrefix prefix = SBPrefixForString(value);
     74   return BuildChunk(chunk_number, safe_browsing::ChunkData::ADD,
     75                     safe_browsing::ChunkData::PREFIX_4B,
     76                     &prefix, sizeof(prefix),
     77                     std::vector<int>());
     78 }
     79 
     80 // Generate an add chunk with two prefixes.
     81 SBChunkData* AddChunkPrefix2Value(int chunk_number,
     82                                   const std::string& value1,
     83                                   const std::string& value2) {
     84   const SBPrefix prefixes[2] = {
     85     SBPrefixForString(value1),
     86     SBPrefixForString(value2),
     87   };
     88   return BuildChunk(chunk_number, safe_browsing::ChunkData::ADD,
     89                     safe_browsing::ChunkData::PREFIX_4B,
     90                     &prefixes[0], sizeof(prefixes),
     91                     std::vector<int>());
     92 }
     93 
     94 // Generate an add chunk with four prefixes.
     95 SBChunkData* AddChunkPrefix4Value(int chunk_number,
     96                                   const std::string& value1,
     97                                   const std::string& value2,
     98                                   const std::string& value3,
     99                                   const std::string& value4) {
    100   const SBPrefix prefixes[4] = {
    101     SBPrefixForString(value1),
    102     SBPrefixForString(value2),
    103     SBPrefixForString(value3),
    104     SBPrefixForString(value4),
    105   };
    106   return BuildChunk(chunk_number, safe_browsing::ChunkData::ADD,
    107                     safe_browsing::ChunkData::PREFIX_4B,
    108                     &prefixes[0], sizeof(prefixes),
    109                     std::vector<int>());
    110 }
    111 
    112 // Generate an add chunk with a full hash generated from |value|.
    113 SBChunkData* AddChunkFullHashValue(int chunk_number,
    114                                    const std::string& value) {
    115   const SBFullHash full_hash = SBFullHashForString(value);
    116   return BuildChunk(chunk_number, safe_browsing::ChunkData::ADD,
    117                     safe_browsing::ChunkData::FULL_32B,
    118                     &full_hash, sizeof(full_hash),
    119                     std::vector<int>());
    120 }
    121 
    122 // Generate an add chunk with two full hashes.
    123 SBChunkData* AddChunkFullHash2Value(int chunk_number,
    124                                    const std::string& value1,
    125                                    const std::string& value2) {
    126   const SBFullHash full_hashes[2] = {
    127     SBFullHashForString(value1),
    128     SBFullHashForString(value2),
    129   };
    130   return BuildChunk(chunk_number, safe_browsing::ChunkData::ADD,
    131                     safe_browsing::ChunkData::FULL_32B,
    132                     &full_hashes[0], sizeof(full_hashes),
    133                     std::vector<int>());
    134 }
    135 
    136 // Generate a sub chunk with a prefix generated from |value|.
    137 SBChunkData* SubChunkPrefixValue(int chunk_number,
    138                                  const std::string& value,
    139                                  int add_chunk_number) {
    140   const SBPrefix prefix = SBPrefixForString(value);
    141   return BuildChunk(chunk_number, safe_browsing::ChunkData::SUB,
    142                     safe_browsing::ChunkData::PREFIX_4B,
    143                     &prefix, sizeof(prefix),
    144                     std::vector<int>(1, add_chunk_number));
    145 }
    146 
    147 // Generate a sub chunk with two prefixes.
    148 SBChunkData* SubChunkPrefix2Value(int chunk_number,
    149                                   const std::string& value1,
    150                                   int add_chunk_number1,
    151                                   const std::string& value2,
    152                                   int add_chunk_number2) {
    153   const SBPrefix prefixes[2] = {
    154     SBPrefixForString(value1),
    155     SBPrefixForString(value2),
    156   };
    157   std::vector<int> add_chunk_numbers;
    158   add_chunk_numbers.push_back(add_chunk_number1);
    159   add_chunk_numbers.push_back(add_chunk_number2);
    160   return BuildChunk(chunk_number, safe_browsing::ChunkData::SUB,
    161                     safe_browsing::ChunkData::PREFIX_4B,
    162                     &prefixes[0], sizeof(prefixes),
    163                     add_chunk_numbers);
    164 }
    165 
    166 // Generate a sub chunk with a full hash generated from |value|.
    167 SBChunkData* SubChunkFullHashValue(int chunk_number,
    168                                    const std::string& value,
    169                                    int add_chunk_number) {
    170   const SBFullHash full_hash = SBFullHashForString(value);
    171   return BuildChunk(chunk_number, safe_browsing::ChunkData::SUB,
    172                     safe_browsing::ChunkData::FULL_32B,
    173                     &full_hash, sizeof(full_hash),
    174                     std::vector<int>(1, add_chunk_number));
    175 }
    176 
    177 // Generate an add chunk with a single full hash for the ip blacklist.
    178 SBChunkData* AddChunkHashedIpValue(int chunk_number,
    179                                    const std::string& ip_str,
    180                                    size_t prefix_size) {
    181   const std::string full_hash_str = HashedIpPrefix(ip_str, prefix_size);
    182   EXPECT_EQ(sizeof(SBFullHash), full_hash_str.size());
    183   SBFullHash full_hash;
    184   std::memcpy(&(full_hash.full_hash), full_hash_str.data(), sizeof(SBFullHash));
    185   return BuildChunk(chunk_number, safe_browsing::ChunkData::ADD,
    186                     safe_browsing::ChunkData::FULL_32B,
    187                     &full_hash, sizeof(full_hash),
    188                     std::vector<int>());
    189 }
    190 
    191 // Prevent DCHECK from killing tests.
    192 // TODO(shess): Pawel disputes the use of this, so the test which uses
    193 // it is DISABLED.  http://crbug.com/56448
    194 class ScopedLogMessageIgnorer {
    195  public:
    196   ScopedLogMessageIgnorer() {
    197     logging::SetLogMessageHandler(&LogMessageIgnorer);
    198   }
    199   ~ScopedLogMessageIgnorer() {
    200     // TODO(shess): Would be better to verify whether anyone else
    201     // changed it, and then restore it to the previous value.
    202     logging::SetLogMessageHandler(NULL);
    203   }
    204 
    205  private:
    206   static bool LogMessageIgnorer(int severity, const char* file, int line,
    207       size_t message_start, const std::string& str) {
    208     // Intercept FATAL, strip the stack backtrace, and log it without
    209     // the crash part.
    210     if (severity == logging::LOG_FATAL) {
    211       size_t newline = str.find('\n');
    212       if (newline != std::string::npos) {
    213         const std::string msg = str.substr(0, newline + 1);
    214         fprintf(stderr, "%s", msg.c_str());
    215         fflush(stderr);
    216       }
    217       return true;
    218     }
    219 
    220     return false;
    221   }
    222 };
    223 
    224 }  // namespace
    225 
    226 class SafeBrowsingDatabaseTest : public PlatformTest {
    227  public:
    228   virtual void SetUp() {
    229     PlatformTest::SetUp();
    230 
    231     // Setup a database in a temporary directory.
    232     ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
    233     database_.reset(new SafeBrowsingDatabaseNew);
    234     database_filename_ =
    235         temp_dir_.path().AppendASCII("SafeBrowsingTestDatabase");
    236     database_->Init(database_filename_);
    237   }
    238 
    239   virtual void TearDown() {
    240     database_.reset();
    241 
    242     PlatformTest::TearDown();
    243   }
    244 
    245   void GetListsInfo(std::vector<SBListChunkRanges>* lists) {
    246     lists->clear();
    247     ASSERT_TRUE(database_->UpdateStarted(lists));
    248     database_->UpdateFinished(true);
    249   }
    250 
    251   // Helper function to do an AddDel or SubDel command.
    252   void DelChunk(const std::string& list,
    253                 int chunk_id,
    254                 bool is_sub_del) {
    255     std::vector<SBChunkDelete> deletes;
    256     SBChunkDelete chunk_delete;
    257     chunk_delete.list_name = list;
    258     chunk_delete.is_sub_del = is_sub_del;
    259     chunk_delete.chunk_del.push_back(ChunkRange(chunk_id));
    260     deletes.push_back(chunk_delete);
    261     database_->DeleteChunks(deletes);
    262   }
    263 
    264   void AddDelChunk(const std::string& list, int chunk_id) {
    265     DelChunk(list, chunk_id, false);
    266   }
    267 
    268   void SubDelChunk(const std::string& list, int chunk_id) {
    269     DelChunk(list, chunk_id, true);
    270   }
    271 
    272   // Utility function for setting up the database for the caching test.
    273   void PopulateDatabaseForCacheTest();
    274 
    275   scoped_ptr<SafeBrowsingDatabaseNew> database_;
    276   base::FilePath database_filename_;
    277   base::ScopedTempDir temp_dir_;
    278 };
    279 
    280 // Tests retrieving list name information.
    281 TEST_F(SafeBrowsingDatabaseTest, ListNameForBrowse) {
    282   std::vector<SBListChunkRanges> lists;
    283   ScopedVector<SBChunkData> chunks;
    284 
    285   chunks.push_back(AddChunkPrefixValue(1, "www.evil.com/malware.html"));
    286   chunks.push_back(AddChunkPrefixValue(2, "www.foo.com/malware.html"));
    287   chunks.push_back(AddChunkPrefixValue(3, "www.whatever.com/malware.html"));
    288 
    289   ASSERT_TRUE(database_->UpdateStarted(&lists));
    290   database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
    291   database_->UpdateFinished(true);
    292 
    293   GetListsInfo(&lists);
    294   ASSERT_LE(1U, lists.size());
    295   EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
    296   EXPECT_EQ("1-3", lists[0].adds);
    297   EXPECT_TRUE(lists[0].subs.empty());
    298 
    299   // Insert a malware sub chunk.
    300   chunks.clear();
    301   chunks.push_back(SubChunkPrefixValue(7, "www.subbed.com/noteveil1.html", 19));
    302 
    303   ASSERT_TRUE(database_->UpdateStarted(&lists));
    304   database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
    305   database_->UpdateFinished(true);
    306 
    307   GetListsInfo(&lists);
    308   ASSERT_LE(1U, lists.size());
    309   EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
    310   EXPECT_EQ("1-3", lists[0].adds);
    311   EXPECT_EQ("7", lists[0].subs);
    312   if (lists.size() == 2) {
    313     // Old style database won't have the second entry since it creates the lists
    314     // when it receives an update containing that list. The filter-based
    315     // database has these values hard coded.
    316     EXPECT_EQ(safe_browsing_util::kPhishingList, lists[1].name);
    317     EXPECT_TRUE(lists[1].adds.empty());
    318     EXPECT_TRUE(lists[1].subs.empty());
    319   }
    320 
    321   // Add phishing chunks.
    322   chunks.clear();
    323   chunks.push_back(AddChunkPrefixValue(47, "www.evil.com/phishing.html"));
    324   chunks.push_back(
    325       SubChunkPrefixValue(200, "www.phishy.com/notevil1.html", 1999));
    326   chunks.push_back(
    327       SubChunkPrefixValue(201, "www.phishy2.com/notevil1.html", 1999));
    328 
    329   ASSERT_TRUE(database_->UpdateStarted(&lists));
    330   database_->InsertChunks(safe_browsing_util::kPhishingList, chunks.get());
    331   database_->UpdateFinished(true);
    332 
    333   GetListsInfo(&lists);
    334   ASSERT_EQ(2U, lists.size());
    335   EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
    336   EXPECT_EQ("1-3", lists[0].adds);
    337   EXPECT_EQ("7", lists[0].subs);
    338   EXPECT_EQ(safe_browsing_util::kPhishingList, lists[1].name);
    339   EXPECT_EQ("47", lists[1].adds);
    340   EXPECT_EQ("200-201", lists[1].subs);
    341 }
    342 
    343 TEST_F(SafeBrowsingDatabaseTest, ListNameForBrowseAndDownload) {
    344   database_.reset();
    345   base::MessageLoop loop;
    346   SafeBrowsingStoreFile* browse_store = new SafeBrowsingStoreFile();
    347   SafeBrowsingStoreFile* download_store = new SafeBrowsingStoreFile();
    348   SafeBrowsingStoreFile* csd_whitelist_store = new SafeBrowsingStoreFile();
    349   SafeBrowsingStoreFile* download_whitelist_store = new SafeBrowsingStoreFile();
    350   SafeBrowsingStoreFile* extension_blacklist_store =
    351       new SafeBrowsingStoreFile();
    352   SafeBrowsingStoreFile* ip_blacklist_store = new SafeBrowsingStoreFile();
    353   database_.reset(new SafeBrowsingDatabaseNew(browse_store,
    354                                               download_store,
    355                                               csd_whitelist_store,
    356                                               download_whitelist_store,
    357                                               extension_blacklist_store,
    358                                               NULL,
    359                                               ip_blacklist_store));
    360   database_->Init(database_filename_);
    361 
    362   ScopedVector<SBChunkData> chunks;
    363 
    364   std::vector<SBListChunkRanges> lists;
    365   ASSERT_TRUE(database_->UpdateStarted(&lists));
    366 
    367   // Insert malware, phish, binurl and bindownload add chunks.
    368   chunks.push_back(AddChunkPrefixValue(1, "www.evil.com/malware.html"));
    369   database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
    370 
    371   chunks.clear();
    372   chunks.push_back(AddChunkPrefixValue(2, "www.foo.com/malware.html"));
    373   database_->InsertChunks(safe_browsing_util::kPhishingList, chunks.get());
    374 
    375   chunks.clear();
    376   chunks.push_back(AddChunkPrefixValue(3, "www.whatever.com/download.html"));
    377   database_->InsertChunks(safe_browsing_util::kBinUrlList, chunks.get());
    378 
    379   chunks.clear();
    380   chunks.push_back(AddChunkFullHashValue(5, "www.forwhitelist.com/a.html"));
    381   database_->InsertChunks(safe_browsing_util::kCsdWhiteList, chunks.get());
    382 
    383   chunks.clear();
    384   chunks.push_back(AddChunkFullHashValue(6, "www.download.com/"));
    385   database_->InsertChunks(safe_browsing_util::kDownloadWhiteList, chunks.get());
    386 
    387   chunks.clear();
    388   chunks.push_back(AddChunkFullHashValue(8,
    389                                          "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
    390                                          "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"));
    391   database_->InsertChunks(safe_browsing_util::kExtensionBlacklist,
    392                           chunks.get());
    393 
    394   chunks.clear();
    395   chunks.push_back(AddChunkHashedIpValue(9, "::ffff:192.168.1.0", 120));
    396   database_->InsertChunks(safe_browsing_util::kIPBlacklist, chunks.get());
    397 
    398   database_->UpdateFinished(true);
    399 
    400   GetListsInfo(&lists);
    401   ASSERT_EQ(7U, lists.size());
    402   EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
    403   EXPECT_EQ("1", lists[0].adds);
    404   EXPECT_TRUE(lists[0].subs.empty());
    405   EXPECT_EQ(safe_browsing_util::kPhishingList, lists[1].name);
    406   EXPECT_EQ("2", lists[1].adds);
    407   EXPECT_TRUE(lists[1].subs.empty());
    408   EXPECT_EQ(safe_browsing_util::kBinUrlList, lists[2].name);
    409   EXPECT_EQ("3", lists[2].adds);
    410   EXPECT_TRUE(lists[2].subs.empty());
    411   EXPECT_EQ(safe_browsing_util::kCsdWhiteList, lists[3].name);
    412   EXPECT_EQ("5", lists[3].adds);
    413   EXPECT_TRUE(lists[3].subs.empty());
    414   EXPECT_EQ(safe_browsing_util::kDownloadWhiteList, lists[4].name);
    415   EXPECT_EQ("6", lists[4].adds);
    416   EXPECT_TRUE(lists[4].subs.empty());
    417   EXPECT_EQ(safe_browsing_util::kExtensionBlacklist, lists[5].name);
    418   EXPECT_EQ("8", lists[5].adds);
    419   EXPECT_TRUE(lists[5].subs.empty());
    420   EXPECT_EQ(safe_browsing_util::kIPBlacklist, lists[6].name);
    421   EXPECT_EQ("9", lists[6].adds);
    422   EXPECT_TRUE(lists[6].subs.empty());
    423 
    424   database_.reset();
    425 }
    426 
    427 // Checks database reading and writing for browse.
    428 TEST_F(SafeBrowsingDatabaseTest, BrowseDatabase) {
    429   std::vector<SBListChunkRanges> lists;
    430   ScopedVector<SBChunkData> chunks;
    431 
    432   chunks.push_back(AddChunkPrefix2Value(1,
    433                                         "www.evil.com/phishing.html",
    434                                         "www.evil.com/malware.html"));
    435   chunks.push_back(AddChunkPrefix4Value(2,
    436                                         "www.evil.com/notevil1.html",
    437                                         "www.evil.com/notevil2.html",
    438                                         "www.good.com/good1.html",
    439                                         "www.good.com/good2.html"));
    440   chunks.push_back(AddChunkPrefixValue(3, "192.168.0.1/malware.html"));
    441   chunks.push_back(AddChunkFullHashValue(7, "www.evil.com/evil.html"));
    442 
    443   ASSERT_TRUE(database_->UpdateStarted(&lists));
    444   database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
    445   database_->UpdateFinished(true);
    446 
    447   // Make sure they were added correctly.
    448   GetListsInfo(&lists);
    449   ASSERT_LE(1U, lists.size());
    450   EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
    451   EXPECT_EQ("1-3,7", lists[0].adds);
    452   EXPECT_TRUE(lists[0].subs.empty());
    453 
    454   std::vector<SBPrefix> prefix_hits;
    455   std::vector<SBFullHashResult> cache_hits;
    456   EXPECT_TRUE(database_->ContainsBrowseUrl(
    457       GURL("http://www.evil.com/phishing.html"), &prefix_hits, &cache_hits));
    458   ASSERT_EQ(1U, prefix_hits.size());
    459   EXPECT_EQ(SBPrefixForString("www.evil.com/phishing.html"), prefix_hits[0]);
    460   EXPECT_TRUE(cache_hits.empty());
    461 
    462   EXPECT_TRUE(database_->ContainsBrowseUrl(
    463       GURL("http://www.evil.com/malware.html"), &prefix_hits, &cache_hits));
    464 
    465   EXPECT_TRUE(database_->ContainsBrowseUrl(
    466       GURL("http://www.evil.com/notevil1.html"), &prefix_hits, &cache_hits));
    467 
    468   EXPECT_TRUE(database_->ContainsBrowseUrl(
    469       GURL("http://www.evil.com/notevil2.html"), &prefix_hits, &cache_hits));
    470 
    471   EXPECT_TRUE(database_->ContainsBrowseUrl(
    472       GURL("http://www.good.com/good1.html"), &prefix_hits, &cache_hits));
    473 
    474   EXPECT_TRUE(database_->ContainsBrowseUrl(
    475       GURL("http://www.good.com/good2.html"), &prefix_hits, &cache_hits));
    476 
    477   EXPECT_TRUE(database_->ContainsBrowseUrl(
    478       GURL("http://192.168.0.1/malware.html"), &prefix_hits, &cache_hits));
    479 
    480   EXPECT_FALSE(database_->ContainsBrowseUrl(
    481       GURL("http://www.evil.com/"), &prefix_hits, &cache_hits));
    482   EXPECT_TRUE(prefix_hits.empty());
    483   EXPECT_TRUE(cache_hits.empty());
    484 
    485   EXPECT_FALSE(database_->ContainsBrowseUrl(
    486       GURL("http://www.evil.com/robots.txt"), &prefix_hits, &cache_hits));
    487 
    488   EXPECT_TRUE(database_->ContainsBrowseUrl(
    489       GURL("http://www.evil.com/evil.html"), &prefix_hits, &cache_hits));
    490   ASSERT_EQ(1U, prefix_hits.size());
    491   EXPECT_EQ(SBPrefixForString("www.evil.com/evil.html"), prefix_hits[0]);
    492 
    493   // Attempt to re-add the first chunk (should be a no-op).
    494   // see bug: http://code.google.com/p/chromium/issues/detail?id=4522
    495   chunks.clear();
    496   chunks.push_back(AddChunkPrefix2Value(1,
    497                                         "www.evil.com/phishing.html",
    498                                         "www.evil.com/malware.html"));
    499   ASSERT_TRUE(database_->UpdateStarted(&lists));
    500   database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
    501   database_->UpdateFinished(true);
    502 
    503   GetListsInfo(&lists);
    504   ASSERT_LE(1U, lists.size());
    505   EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
    506   EXPECT_EQ("1-3,7", lists[0].adds);
    507   EXPECT_TRUE(lists[0].subs.empty());
    508 
    509   // Test removing a single prefix from the add chunk.
    510   chunks.clear();
    511   chunks.push_back(SubChunkPrefixValue(4, "www.evil.com/notevil1.html", 2));
    512   ASSERT_TRUE(database_->UpdateStarted(&lists));
    513   database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
    514   database_->UpdateFinished(true);
    515 
    516   EXPECT_TRUE(database_->ContainsBrowseUrl(
    517       GURL("http://www.evil.com/phishing.html"), &prefix_hits, &cache_hits));
    518   ASSERT_EQ(1U, prefix_hits.size());
    519   EXPECT_EQ(SBPrefixForString("www.evil.com/phishing.html"), prefix_hits[0]);
    520   EXPECT_TRUE(cache_hits.empty());
    521 
    522   EXPECT_FALSE(database_->ContainsBrowseUrl(
    523       GURL("http://www.evil.com/notevil1.html"), &prefix_hits, &cache_hits));
    524   EXPECT_TRUE(prefix_hits.empty());
    525   EXPECT_TRUE(cache_hits.empty());
    526 
    527   EXPECT_TRUE(database_->ContainsBrowseUrl(
    528       GURL("http://www.evil.com/notevil2.html"), &prefix_hits, &cache_hits));
    529 
    530   EXPECT_TRUE(database_->ContainsBrowseUrl(
    531       GURL("http://www.good.com/good1.html"), &prefix_hits, &cache_hits));
    532 
    533   EXPECT_TRUE(database_->ContainsBrowseUrl(
    534       GURL("http://www.good.com/good2.html"), &prefix_hits, &cache_hits));
    535 
    536   GetListsInfo(&lists);
    537   ASSERT_LE(1U, lists.size());
    538   EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
    539   EXPECT_EQ("1-3,7", lists[0].adds);
    540   EXPECT_EQ("4", lists[0].subs);
    541 
    542   // Test the same sub chunk again.  This should be a no-op.
    543   // see bug: http://code.google.com/p/chromium/issues/detail?id=4522
    544   chunks.clear();
    545   chunks.push_back(SubChunkPrefixValue(4, "www.evil.com/notevil1.html", 2));
    546 
    547   ASSERT_TRUE(database_->UpdateStarted(&lists));
    548   database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
    549   database_->UpdateFinished(true);
    550 
    551   GetListsInfo(&lists);
    552   ASSERT_LE(1U, lists.size());
    553   EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
    554   EXPECT_EQ("1-3,7", lists[0].adds);
    555   EXPECT_EQ("4", lists[0].subs);
    556 
    557   // Test removing all the prefixes from an add chunk.
    558   ASSERT_TRUE(database_->UpdateStarted(&lists));
    559   AddDelChunk(safe_browsing_util::kMalwareList, 2);
    560   database_->UpdateFinished(true);
    561 
    562   EXPECT_FALSE(database_->ContainsBrowseUrl(
    563       GURL("http://www.evil.com/notevil2.html"), &prefix_hits, &cache_hits));
    564 
    565   EXPECT_FALSE(database_->ContainsBrowseUrl(
    566       GURL("http://www.good.com/good1.html"), &prefix_hits, &cache_hits));
    567 
    568   EXPECT_FALSE(database_->ContainsBrowseUrl(
    569       GURL("http://www.good.com/good2.html"), &prefix_hits, &cache_hits));
    570 
    571   GetListsInfo(&lists);
    572   ASSERT_LE(1U, lists.size());
    573   EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
    574   EXPECT_EQ("1,3,7", lists[0].adds);
    575   EXPECT_EQ("4", lists[0].subs);
    576 
    577   // The adddel command exposed a bug in the transaction code where any
    578   // transaction after it would fail.  Add a dummy entry and remove it to
    579   // make sure the transcation works fine.
    580   chunks.clear();
    581   chunks.push_back(AddChunkPrefixValue(44, "www.redherring.com/index.html"));
    582   ASSERT_TRUE(database_->UpdateStarted(&lists));
    583   database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
    584 
    585   // Now remove the dummy entry.  If there are any problems with the
    586   // transactions, asserts will fire.
    587   AddDelChunk(safe_browsing_util::kMalwareList, 44);
    588 
    589   // Test the subdel command.
    590   SubDelChunk(safe_browsing_util::kMalwareList, 4);
    591   database_->UpdateFinished(true);
    592 
    593   GetListsInfo(&lists);
    594   ASSERT_LE(1U, lists.size());
    595   EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
    596   EXPECT_EQ("1,3,7", lists[0].adds);
    597   EXPECT_TRUE(lists[0].subs.empty());
    598 
    599   // Test a sub command coming in before the add.
    600   chunks.clear();
    601   chunks.push_back(SubChunkPrefix2Value(5,
    602                                         "www.notevilanymore.com/index.html",
    603                                         10,
    604                                         "www.notevilanymore.com/good.html",
    605                                         10));
    606   ASSERT_TRUE(database_->UpdateStarted(&lists));
    607   database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
    608   database_->UpdateFinished(true);
    609 
    610   EXPECT_FALSE(database_->ContainsBrowseUrl(
    611       GURL("http://www.notevilanymore.com/index.html"),
    612       &prefix_hits,
    613       &cache_hits));
    614 
    615   // Now insert the tardy add chunk and we don't expect them to appear
    616   // in database because of the previous sub chunk.
    617   chunks.clear();
    618   chunks.push_back(AddChunkPrefix2Value(10,
    619                                         "www.notevilanymore.com/index.html",
    620                                         "www.notevilanymore.com/good.html"));
    621   ASSERT_TRUE(database_->UpdateStarted(&lists));
    622   database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
    623   database_->UpdateFinished(true);
    624 
    625   EXPECT_FALSE(database_->ContainsBrowseUrl(
    626       GURL("http://www.notevilanymore.com/index.html"),
    627       &prefix_hits,
    628       &cache_hits));
    629 
    630   EXPECT_FALSE(database_->ContainsBrowseUrl(
    631       GURL("http://www.notevilanymore.com/good.html"),
    632       &prefix_hits,
    633       &cache_hits));
    634 
    635   // Reset and reload the database.  The database will rely on the prefix set.
    636   database_.reset(new SafeBrowsingDatabaseNew);
    637   database_->Init(database_filename_);
    638 
    639   // Check that a prefix still hits.
    640   EXPECT_TRUE(database_->ContainsBrowseUrl(
    641       GURL("http://www.evil.com/phishing.html"), &prefix_hits, &cache_hits));
    642   ASSERT_EQ(1U, prefix_hits.size());
    643   EXPECT_EQ(SBPrefixForString("www.evil.com/phishing.html"), prefix_hits[0]);
    644 
    645   // Also check that it's not just always returning true in this case.
    646   EXPECT_FALSE(database_->ContainsBrowseUrl(
    647       GURL("http://www.evil.com/"), &prefix_hits, &cache_hits));
    648 
    649   // Check that the full hash is still present.
    650   EXPECT_TRUE(database_->ContainsBrowseUrl(
    651       GURL("http://www.evil.com/evil.html"), &prefix_hits, &cache_hits));
    652   ASSERT_EQ(1U, prefix_hits.size());
    653   EXPECT_EQ(SBPrefixForString("www.evil.com/evil.html"), prefix_hits[0]);
    654 }
    655 
    656 // Test adding zero length chunks to the database.
    657 TEST_F(SafeBrowsingDatabaseTest, ZeroSizeChunk) {
    658   std::vector<SBListChunkRanges> lists;
    659   ScopedVector<SBChunkData> chunks;
    660 
    661   // Populate with a couple of normal chunks.
    662   chunks.push_back(AddChunkPrefix2Value(1,
    663                                         "www.test.com/test1.html",
    664                                         "www.test.com/test2.html"));
    665   chunks.push_back(AddChunkPrefix2Value(10,
    666                                         "www.random.com/random1.html",
    667                                         "www.random.com/random2.html"));
    668 
    669   ASSERT_TRUE(database_->UpdateStarted(&lists));
    670   database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
    671   database_->UpdateFinished(true);
    672 
    673   // Add an empty ADD and SUB chunk.
    674   GetListsInfo(&lists);
    675   ASSERT_LE(1U, lists.size());
    676   EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
    677   EXPECT_EQ("1,10", lists[0].adds);
    678   EXPECT_TRUE(lists[0].subs.empty());
    679 
    680   chunks.clear();
    681   chunks.push_back(BuildChunk(19, safe_browsing::ChunkData::ADD,
    682                               safe_browsing::ChunkData::PREFIX_4B,
    683                               NULL, 0, std::vector<int>()));
    684   chunks.push_back(BuildChunk(7, safe_browsing::ChunkData::SUB,
    685                               safe_browsing::ChunkData::PREFIX_4B,
    686                               NULL, 0, std::vector<int>()));
    687 
    688   ASSERT_TRUE(database_->UpdateStarted(&lists));
    689   database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
    690   database_->UpdateFinished(true);
    691 
    692   GetListsInfo(&lists);
    693   ASSERT_LE(1U, lists.size());
    694   EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
    695   EXPECT_EQ("1,10,19", lists[0].adds);
    696   EXPECT_EQ("7", lists[0].subs);
    697 
    698   // Add an empty chunk along with a couple that contain data. This should
    699   // result in the chunk range being reduced in size.
    700   chunks.clear();
    701   chunks.push_back(AddChunkPrefixValue(20, "www.notempty.com/full1.html"));
    702   chunks.push_back(BuildChunk(21, safe_browsing::ChunkData::ADD,
    703                               safe_browsing::ChunkData::PREFIX_4B,
    704                               NULL, 0, std::vector<int>()));
    705   chunks.push_back(AddChunkPrefixValue(22, "www.notempty.com/full2.html"));
    706 
    707   ASSERT_TRUE(database_->UpdateStarted(&lists));
    708   database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
    709   database_->UpdateFinished(true);
    710 
    711   std::vector<SBPrefix> prefix_hits;
    712   std::vector<SBFullHashResult> cache_hits;
    713   EXPECT_TRUE(database_->ContainsBrowseUrl(
    714       GURL("http://www.notempty.com/full1.html"), &prefix_hits, &cache_hits));
    715   EXPECT_TRUE(database_->ContainsBrowseUrl(
    716       GURL("http://www.notempty.com/full2.html"), &prefix_hits, &cache_hits));
    717 
    718   GetListsInfo(&lists);
    719   ASSERT_LE(1U, lists.size());
    720   EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
    721   EXPECT_EQ("1,10,19-22", lists[0].adds);
    722   EXPECT_EQ("7", lists[0].subs);
    723 
    724   // Handle AddDel and SubDel commands for empty chunks.
    725   ASSERT_TRUE(database_->UpdateStarted(&lists));
    726   AddDelChunk(safe_browsing_util::kMalwareList, 21);
    727   database_->UpdateFinished(true);
    728 
    729   GetListsInfo(&lists);
    730   ASSERT_LE(1U, lists.size());
    731   EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
    732   EXPECT_EQ("1,10,19-20,22", lists[0].adds);
    733   EXPECT_EQ("7", lists[0].subs);
    734 
    735   ASSERT_TRUE(database_->UpdateStarted(&lists));
    736   SubDelChunk(safe_browsing_util::kMalwareList, 7);
    737   database_->UpdateFinished(true);
    738 
    739   GetListsInfo(&lists);
    740   ASSERT_LE(1U, lists.size());
    741   EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
    742   EXPECT_EQ("1,10,19-20,22", lists[0].adds);
    743   EXPECT_TRUE(lists[0].subs.empty());
    744 }
    745 
    746 // Utility function for setting up the database for the caching test.
    747 void SafeBrowsingDatabaseTest::PopulateDatabaseForCacheTest() {
    748   // Add a simple chunk with one hostkey and cache it.
    749   ScopedVector<SBChunkData> chunks;
    750   chunks.push_back(AddChunkPrefix2Value(1,
    751                                         "www.evil.com/phishing.html",
    752                                         "www.evil.com/malware.html"));
    753 
    754   std::vector<SBListChunkRanges> lists;
    755   ASSERT_TRUE(database_->UpdateStarted(&lists));
    756   database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
    757   database_->UpdateFinished(true);
    758 
    759   // Add the GetHash results to the cache.
    760   SBFullHashResult full_hash;
    761   full_hash.hash = SBFullHashForString("www.evil.com/phishing.html");
    762   full_hash.list_id = safe_browsing_util::MALWARE;
    763 
    764   std::vector<SBFullHashResult> results;
    765   results.push_back(full_hash);
    766 
    767   full_hash.hash = SBFullHashForString("www.evil.com/malware.html");
    768   results.push_back(full_hash);
    769 
    770   std::vector<SBPrefix> prefixes;
    771   database_->CacheHashResults(prefixes, results, kCacheLifetime);
    772 }
    773 
    774 TEST_F(SafeBrowsingDatabaseTest, HashCaching) {
    775   PopulateDatabaseForCacheTest();
    776 
    777   // We should have both full hashes in the cache.
    778   EXPECT_EQ(2U, database_->cached_browse_hashes_.size());
    779 
    780   // Test the cache lookup for the first prefix.
    781   std::vector<SBPrefix> prefix_hits;
    782   std::vector<SBFullHashResult> cache_hits;
    783   database_->ContainsBrowseUrl(
    784       GURL("http://www.evil.com/phishing.html"), &prefix_hits, &cache_hits);
    785   ASSERT_EQ(1U, cache_hits.size());
    786   EXPECT_TRUE(SBFullHashEqual(
    787       cache_hits[0].hash, SBFullHashForString("www.evil.com/phishing.html")));
    788 
    789   prefix_hits.clear();
    790   cache_hits.clear();
    791 
    792   // Test the cache lookup for the second prefix.
    793   database_->ContainsBrowseUrl(
    794       GURL("http://www.evil.com/malware.html"), &prefix_hits, &cache_hits);
    795   ASSERT_EQ(1U, cache_hits.size());
    796   EXPECT_TRUE(SBFullHashEqual(
    797       cache_hits[0].hash, SBFullHashForString("www.evil.com/malware.html")));
    798 
    799   prefix_hits.clear();
    800   cache_hits.clear();
    801 
    802   // Test removing a prefix via a sub chunk.
    803   ScopedVector<SBChunkData> chunks;
    804   chunks.push_back(SubChunkPrefixValue(2, "www.evil.com/phishing.html", 1));
    805 
    806   std::vector<SBListChunkRanges> lists;
    807   ASSERT_TRUE(database_->UpdateStarted(&lists));
    808   database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
    809   database_->UpdateFinished(true);
    810 
    811   // This prefix should still be there, but cached fullhash should be gone.
    812   EXPECT_TRUE(database_->ContainsBrowseUrl(
    813       GURL("http://www.evil.com/malware.html"), &prefix_hits, &cache_hits));
    814   ASSERT_EQ(1U, prefix_hits.size());
    815   EXPECT_EQ(SBPrefixForString("www.evil.com/malware.html"), prefix_hits[0]);
    816   EXPECT_TRUE(cache_hits.empty());
    817   prefix_hits.clear();
    818   cache_hits.clear();
    819 
    820   // This prefix should be gone.
    821   database_->ContainsBrowseUrl(
    822       GURL("http://www.evil.com/phishing.html"), &prefix_hits, &cache_hits);
    823   EXPECT_TRUE(prefix_hits.empty());
    824   EXPECT_TRUE(cache_hits.empty());
    825 
    826   prefix_hits.clear();
    827   cache_hits.clear();
    828 
    829   // Test that an AddDel for the original chunk removes the last cached entry.
    830   ASSERT_TRUE(database_->UpdateStarted(&lists));
    831   AddDelChunk(safe_browsing_util::kMalwareList, 1);
    832   database_->UpdateFinished(true);
    833   database_->ContainsBrowseUrl(
    834       GURL("http://www.evil.com/malware.html"), &prefix_hits, &cache_hits);
    835   EXPECT_TRUE(cache_hits.empty());
    836   EXPECT_TRUE(database_->cached_browse_hashes_.empty());
    837 
    838   prefix_hits.clear();
    839   cache_hits.clear();
    840 
    841   // Test that the cache won't return expired values. First we have to adjust
    842   // the cached entries' received time to make them older, since the database
    843   // cache insert uses Time::Now(). First, store some entries.
    844   PopulateDatabaseForCacheTest();
    845 
    846   std::vector<SBFullHashCached>* hash_cache = &database_->cached_browse_hashes_;
    847   EXPECT_EQ(2U, hash_cache->size());
    848 
    849   // Now adjust one of the entries times to be expired.
    850   const Time expired = Time::Now() - TimeDelta::FromMinutes(1);
    851   const SBPrefix key = SBPrefixForString("www.evil.com/malware.html");
    852   std::vector<SBFullHashCached>::iterator iter;
    853   for (iter = hash_cache->begin(); iter != hash_cache->end(); ++iter) {
    854     if (iter->hash.prefix == key) {
    855       iter->expire_after = expired;
    856       break;
    857     }
    858   }
    859   EXPECT_TRUE(iter != hash_cache->end());
    860 
    861   database_->ContainsBrowseUrl(
    862       GURL("http://www.evil.com/malware.html"), &prefix_hits, &cache_hits);
    863   EXPECT_TRUE(cache_hits.empty());
    864 
    865   // This entry should still exist.
    866   database_->ContainsBrowseUrl(
    867       GURL("http://www.evil.com/phishing.html"), &prefix_hits, &cache_hits);
    868   EXPECT_EQ(1U, cache_hits.size());
    869 
    870   // Testing prefix miss caching. First, we clear out the existing database,
    871   // Since PopulateDatabaseForCacheTest() doesn't handle adding duplicate
    872   // chunks.
    873   ASSERT_TRUE(database_->UpdateStarted(&lists));
    874   AddDelChunk(safe_browsing_util::kMalwareList, 1);
    875   database_->UpdateFinished(true);
    876 
    877   std::vector<SBPrefix> prefix_misses;
    878   std::vector<SBFullHashResult> empty_full_hash;
    879   prefix_misses.push_back(SBPrefixForString("http://www.bad.com/malware.html"));
    880   prefix_misses.push_back(
    881       SBPrefixForString("http://www.bad.com/phishing.html"));
    882   database_->CacheHashResults(prefix_misses, empty_full_hash, kCacheLifetime);
    883 
    884   // Prefixes with no full results are misses.
    885   EXPECT_EQ(2U, database_->prefix_miss_cache_.size());
    886 
    887   // Update the database.
    888   PopulateDatabaseForCacheTest();
    889 
    890   // Prefix miss cache should be cleared.
    891   EXPECT_TRUE(database_->prefix_miss_cache_.empty());
    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   prefix_hits.clear();
    897   cache_hits.clear();
    898   prefix_misses.clear();
    899   empty_full_hash.clear();
    900   prefix_misses.push_back(SBPrefixForString("www.evil.com/phishing.html"));
    901   database_->CacheHashResults(prefix_misses, empty_full_hash, kCacheLifetime);
    902   EXPECT_FALSE(database_->ContainsBrowseUrl(
    903       GURL("http://www.evil.com/phishing.html"), &prefix_hits, &cache_hits));
    904 
    905   prefix_hits.clear();
    906   cache_hits.clear();
    907 
    908   // Test receiving a full add chunk.
    909   chunks.clear();
    910   chunks.push_back(AddChunkFullHash2Value(20,
    911                                           "www.fullevil.com/bad1.html",
    912                                           "www.fullevil.com/bad2.html"));
    913   ASSERT_TRUE(database_->UpdateStarted(&lists));
    914   database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
    915   database_->UpdateFinished(true);
    916 
    917   EXPECT_TRUE(database_->ContainsBrowseUrl(
    918       GURL("http://www.fullevil.com/bad1.html"), &prefix_hits, &cache_hits));
    919   ASSERT_EQ(1U, prefix_hits.size());
    920   EXPECT_EQ(SBPrefixForString("www.fullevil.com/bad1.html"), prefix_hits[0]);
    921   EXPECT_TRUE(cache_hits.empty());
    922   prefix_hits.clear();
    923   cache_hits.clear();
    924 
    925   EXPECT_TRUE(database_->ContainsBrowseUrl(
    926       GURL("http://www.fullevil.com/bad2.html"), &prefix_hits, &cache_hits));
    927   ASSERT_EQ(1U, prefix_hits.size());
    928   EXPECT_EQ(SBPrefixForString("www.fullevil.com/bad2.html"), prefix_hits[0]);
    929   EXPECT_TRUE(cache_hits.empty());
    930   prefix_hits.clear();
    931   cache_hits.clear();
    932 
    933   // Test receiving a full sub chunk, which will remove one of the full adds.
    934   chunks.clear();
    935   chunks.push_back(SubChunkFullHashValue(200,
    936                                          "www.fullevil.com/bad1.html",
    937                                          20));
    938   ASSERT_TRUE(database_->UpdateStarted(&lists));
    939   database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
    940   database_->UpdateFinished(true);
    941 
    942   EXPECT_FALSE(database_->ContainsBrowseUrl(
    943       GURL("http://www.fullevil.com/bad1.html"), &prefix_hits, &cache_hits));
    944   EXPECT_TRUE(prefix_hits.empty());
    945   EXPECT_TRUE(cache_hits.empty());
    946 
    947   // There should be one remaining full add.
    948   EXPECT_TRUE(database_->ContainsBrowseUrl(
    949       GURL("http://www.fullevil.com/bad2.html"), &prefix_hits, &cache_hits));
    950   ASSERT_EQ(1U, prefix_hits.size());
    951   EXPECT_EQ(SBPrefixForString("www.fullevil.com/bad2.html"), prefix_hits[0]);
    952   EXPECT_TRUE(cache_hits.empty());
    953   prefix_hits.clear();
    954   cache_hits.clear();
    955 
    956   // Now test an AddDel for the remaining full add.
    957   ASSERT_TRUE(database_->UpdateStarted(&lists));
    958   AddDelChunk(safe_browsing_util::kMalwareList, 20);
    959   database_->UpdateFinished(true);
    960 
    961   EXPECT_FALSE(database_->ContainsBrowseUrl(
    962       GURL("http://www.fullevil.com/bad1.html"), &prefix_hits, &cache_hits));
    963   EXPECT_FALSE(database_->ContainsBrowseUrl(
    964       GURL("http://www.fullevil.com/bad2.html"), &prefix_hits, &cache_hits));
    965 
    966   // Add a fullhash which has a prefix collision for a known url.
    967   static const char kExampleFine[] = "www.example.com/fine.html";
    968   static const char kExampleCollision[] =
    969       "www.example.com/3123364814/malware.htm";
    970   ASSERT_EQ(SBPrefixForString(kExampleFine),
    971             SBPrefixForString(kExampleCollision));
    972   ASSERT_TRUE(database_->UpdateStarted(&lists));
    973   {
    974     ScopedVector<SBChunkData> chunks;
    975     chunks.push_back(AddChunkPrefixValue(21, kExampleCollision));
    976     database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
    977   }
    978   database_->UpdateFinished(true);
    979 
    980   // Cache gethash response for |kExampleCollision|.
    981   {
    982     SBFullHashResult result;
    983     result.hash = SBFullHashForString(kExampleCollision);
    984     result.list_id = safe_browsing_util::MALWARE;
    985     database_->CacheHashResults(std::vector<SBPrefix>(1, result.hash.prefix),
    986                                 std::vector<SBFullHashResult>(1, result),
    987                                 kCacheLifetime);
    988   }
    989 
    990   // Expect a prefix hit due to the collision between |kExampleFine| and
    991   // |kExampleCollision|, with the gethash showing only |kExampleCollision|.
    992   EXPECT_TRUE(database_->ContainsBrowseUrl(
    993       GURL(std::string("http://") + kExampleFine), &prefix_hits, &cache_hits));
    994   ASSERT_EQ(1U, prefix_hits.size());
    995   EXPECT_EQ(SBPrefixForString(kExampleFine), prefix_hits[0]);
    996   ASSERT_EQ(1U, cache_hits.size());
    997   EXPECT_TRUE(SBFullHashEqual(cache_hits[0].hash,
    998                               SBFullHashForString(kExampleCollision)));
    999 }
   1000 
   1001 // Test that corrupt databases are appropriately handled, even if the
   1002 // corruption is detected in the midst of the update.
   1003 // TODO(shess): Disabled until ScopedLogMessageIgnorer resolved.
   1004 // http://crbug.com/56448
   1005 TEST_F(SafeBrowsingDatabaseTest, DISABLED_FileCorruptionHandling) {
   1006   // Re-create the database in a captive message loop so that we can
   1007   // influence task-posting.  Database specifically needs to the
   1008   // file-backed.
   1009   database_.reset();
   1010   base::MessageLoop loop;
   1011   SafeBrowsingStoreFile* store = new SafeBrowsingStoreFile();
   1012   database_.reset(new SafeBrowsingDatabaseNew(store, NULL, NULL, NULL, NULL,
   1013                                               NULL, NULL));
   1014   database_->Init(database_filename_);
   1015 
   1016   // This will cause an empty database to be created.
   1017   std::vector<SBListChunkRanges> lists;
   1018   ASSERT_TRUE(database_->UpdateStarted(&lists));
   1019   database_->UpdateFinished(true);
   1020 
   1021   // Create a sub chunk to insert.
   1022   ScopedVector<SBChunkData> chunks;
   1023   chunks.push_back(SubChunkPrefixValue(7,
   1024                                        "www.subbed.com/notevil1.html",
   1025                                        19));
   1026 
   1027   // Corrupt the file by corrupting the checksum, which is not checked
   1028   // until the entire table is read in |UpdateFinished()|.
   1029   FILE* fp = base::OpenFile(database_filename_, "r+");
   1030   ASSERT_TRUE(fp);
   1031   ASSERT_NE(-1, fseek(fp, -8, SEEK_END));
   1032   for (size_t i = 0; i < 8; ++i) {
   1033     fputc('!', fp);
   1034   }
   1035   fclose(fp);
   1036 
   1037   {
   1038     // The following code will cause DCHECKs, so suppress the crashes.
   1039     ScopedLogMessageIgnorer ignorer;
   1040 
   1041     // Start an update.  The insert will fail due to corruption.
   1042     ASSERT_TRUE(database_->UpdateStarted(&lists));
   1043     database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
   1044     database_->UpdateFinished(true);
   1045 
   1046     // Database file still exists until the corruption handler has run.
   1047     EXPECT_TRUE(base::PathExists(database_filename_));
   1048 
   1049     // Flush through the corruption-handler task.
   1050     VLOG(1) << "Expect failed check on: SafeBrowsing database reset";
   1051     base::MessageLoop::current()->RunUntilIdle();
   1052   }
   1053 
   1054   // Database file should not exist.
   1055   EXPECT_FALSE(base::PathExists(database_filename_));
   1056 
   1057   // Run the update again successfully.
   1058   ASSERT_TRUE(database_->UpdateStarted(&lists));
   1059   database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
   1060   database_->UpdateFinished(true);
   1061   EXPECT_TRUE(base::PathExists(database_filename_));
   1062 
   1063   database_.reset();
   1064 }
   1065 
   1066 // Checks database reading and writing.
   1067 TEST_F(SafeBrowsingDatabaseTest, ContainsDownloadUrl) {
   1068   database_.reset();
   1069   base::MessageLoop loop;
   1070   SafeBrowsingStoreFile* browse_store = new SafeBrowsingStoreFile();
   1071   SafeBrowsingStoreFile* download_store = new SafeBrowsingStoreFile();
   1072   SafeBrowsingStoreFile* csd_whitelist_store = new SafeBrowsingStoreFile();
   1073   database_.reset(new SafeBrowsingDatabaseNew(browse_store,
   1074                                               download_store,
   1075                                               csd_whitelist_store,
   1076                                               NULL,
   1077                                               NULL,
   1078                                               NULL,
   1079                                               NULL));
   1080   database_->Init(database_filename_);
   1081 
   1082   const char kEvil1Url1[] = "www.evil1.com/download1/";
   1083   const char kEvil1Url2[] = "www.evil1.com/download2.html";
   1084 
   1085   // Add a simple chunk with one hostkey for download url list.
   1086   ScopedVector<SBChunkData> chunks;
   1087   chunks.push_back(AddChunkPrefix2Value(1, kEvil1Url1, kEvil1Url2));
   1088 
   1089   std::vector<SBListChunkRanges> lists;
   1090   ASSERT_TRUE(database_->UpdateStarted(&lists));
   1091   database_->InsertChunks(safe_browsing_util::kBinUrlList, chunks.get());
   1092   database_->UpdateFinished(true);
   1093 
   1094   std::vector<SBPrefix> prefix_hits;
   1095   std::vector<GURL> urls(1);
   1096 
   1097   urls[0] = GURL(std::string("http://") + kEvil1Url1);
   1098   EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits));
   1099   ASSERT_EQ(1U, prefix_hits.size());
   1100   EXPECT_EQ(SBPrefixForString(kEvil1Url1), prefix_hits[0]);
   1101 
   1102   urls[0] = GURL(std::string("http://") + kEvil1Url2);
   1103   EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits));
   1104   ASSERT_EQ(1U, prefix_hits.size());
   1105   EXPECT_EQ(SBPrefixForString(kEvil1Url2), prefix_hits[0]);
   1106 
   1107   urls[0] = GURL(std::string("https://") + kEvil1Url2);
   1108   EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits));
   1109   ASSERT_EQ(1U, prefix_hits.size());
   1110   EXPECT_EQ(SBPrefixForString(kEvil1Url2), prefix_hits[0]);
   1111 
   1112   urls[0] = GURL(std::string("ftp://") + kEvil1Url2);
   1113   EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits));
   1114   ASSERT_EQ(1U, prefix_hits.size());
   1115   EXPECT_EQ(SBPrefixForString(kEvil1Url2), prefix_hits[0]);
   1116 
   1117   urls[0] = GURL("http://www.randomevil.com");
   1118   EXPECT_FALSE(database_->ContainsDownloadUrl(urls, &prefix_hits));
   1119 
   1120   // Should match with query args stripped.
   1121   urls[0] = GURL(std::string("http://") + kEvil1Url2 + "?blah");
   1122   EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits));
   1123   ASSERT_EQ(1U, prefix_hits.size());
   1124   EXPECT_EQ(SBPrefixForString(kEvil1Url2), prefix_hits[0]);
   1125 
   1126   // Should match with extra path stuff and query args stripped.
   1127   urls[0] = GURL(std::string("http://") + kEvil1Url1 + "foo/bar?blah");
   1128   EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits));
   1129   ASSERT_EQ(1U, prefix_hits.size());
   1130   EXPECT_EQ(SBPrefixForString(kEvil1Url1), prefix_hits[0]);
   1131 
   1132   // First hit in redirect chain is malware.
   1133   urls.clear();
   1134   urls.push_back(GURL(std::string("http://") + kEvil1Url1));
   1135   urls.push_back(GURL("http://www.randomevil.com"));
   1136   EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits));
   1137   ASSERT_EQ(1U, prefix_hits.size());
   1138   EXPECT_EQ(SBPrefixForString(kEvil1Url1), prefix_hits[0]);
   1139 
   1140   // Middle hit in redirect chain is malware.
   1141   urls.clear();
   1142   urls.push_back(GURL("http://www.randomevil.com"));
   1143   urls.push_back(GURL(std::string("http://") + kEvil1Url1));
   1144   urls.push_back(GURL("http://www.randomevil2.com"));
   1145   EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits));
   1146   ASSERT_EQ(1U, prefix_hits.size());
   1147   EXPECT_EQ(SBPrefixForString(kEvil1Url1), prefix_hits[0]);
   1148 
   1149   // Final hit in redirect chain is malware.
   1150   urls.clear();
   1151   urls.push_back(GURL("http://www.randomevil.com"));
   1152   urls.push_back(GURL(std::string("http://") + kEvil1Url1));
   1153   EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits));
   1154   ASSERT_EQ(1U, prefix_hits.size());
   1155   EXPECT_EQ(SBPrefixForString(kEvil1Url1), prefix_hits[0]);
   1156 
   1157   // Multiple hits in redirect chain are in malware list.
   1158   urls.clear();
   1159   urls.push_back(GURL(std::string("http://") + kEvil1Url1));
   1160   urls.push_back(GURL(std::string("https://") + kEvil1Url2));
   1161   EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits));
   1162   ASSERT_EQ(2U, prefix_hits.size());
   1163   EXPECT_EQ(SBPrefixForString(kEvil1Url1), prefix_hits[0]);
   1164   EXPECT_EQ(SBPrefixForString(kEvil1Url2), prefix_hits[1]);
   1165   database_.reset();
   1166 }
   1167 
   1168 // Checks that the whitelists are handled properly.
   1169 TEST_F(SafeBrowsingDatabaseTest, Whitelists) {
   1170   database_.reset();
   1171 
   1172   // We expect all calls to ContainsCsdWhitelistedUrl in particular to be made
   1173   // from the IO thread.  In general the whitelist lookups are thread-safe.
   1174   content::TestBrowserThreadBundle thread_bundle_;
   1175 
   1176   // If the whitelist is disabled everything should match the whitelist.
   1177   database_.reset(new SafeBrowsingDatabaseNew(new SafeBrowsingStoreFile(),
   1178                                               NULL, NULL, NULL, NULL, NULL,
   1179                                               NULL));
   1180   database_->Init(database_filename_);
   1181   EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl(
   1182       GURL(std::string("http://www.phishing.com/"))));
   1183   EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl(
   1184       GURL(std::string("http://www.phishing.com/"))));
   1185   EXPECT_TRUE(database_->ContainsDownloadWhitelistedString("asdf"));
   1186 
   1187   SafeBrowsingStoreFile* browse_store = new SafeBrowsingStoreFile();
   1188   SafeBrowsingStoreFile* csd_whitelist_store = new SafeBrowsingStoreFile();
   1189   SafeBrowsingStoreFile* download_whitelist_store = new SafeBrowsingStoreFile();
   1190   SafeBrowsingStoreFile* extension_blacklist_store =
   1191       new SafeBrowsingStoreFile();
   1192   database_.reset(new SafeBrowsingDatabaseNew(browse_store, NULL,
   1193                                               csd_whitelist_store,
   1194                                               download_whitelist_store,
   1195                                               extension_blacklist_store,
   1196                                               NULL, NULL));
   1197   database_->Init(database_filename_);
   1198 
   1199   const char kGood1Host[] = "www.good1.com/";
   1200   const char kGood1Url1[] = "www.good1.com/a/b.html";
   1201   const char kGood1Url2[] = "www.good1.com/b/";
   1202 
   1203   const char kGood2Url1[] = "www.good2.com/c";  // Should match '/c/bla'.
   1204 
   1205   // good3.com/a/b/c/d/e/f/g/ should match because it's a whitelist.
   1206   const char kGood3Url1[] = "good3.com/";
   1207 
   1208   const char kGoodString[] = "good_string";
   1209 
   1210   ScopedVector<SBChunkData> csd_chunks;
   1211   ScopedVector<SBChunkData> download_chunks;
   1212 
   1213   // Add two simple chunks to the csd whitelist.
   1214   csd_chunks.push_back(AddChunkFullHash2Value(1, kGood1Url1, kGood1Url2));
   1215   csd_chunks.push_back(AddChunkFullHashValue(2, kGood2Url1));
   1216   download_chunks.push_back(AddChunkFullHashValue(2, kGood2Url1));
   1217   download_chunks.push_back(AddChunkFullHashValue(3, kGoodString));
   1218   download_chunks.push_back(AddChunkFullHashValue(4, kGood3Url1));
   1219 
   1220   std::vector<SBListChunkRanges> lists;
   1221   ASSERT_TRUE(database_->UpdateStarted(&lists));
   1222   database_->InsertChunks(safe_browsing_util::kCsdWhiteList, csd_chunks.get());
   1223   database_->InsertChunks(safe_browsing_util::kDownloadWhiteList,
   1224                           download_chunks.get());
   1225   database_->UpdateFinished(true);
   1226 
   1227   EXPECT_FALSE(database_->ContainsCsdWhitelistedUrl(
   1228       GURL(std::string("http://") + kGood1Host)));
   1229 
   1230   EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
   1231       GURL(std::string("http://") + kGood1Url1)));
   1232   EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
   1233       GURL(std::string("http://") + kGood1Url1 + "?a=b")));
   1234 
   1235   EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
   1236       GURL(std::string("http://") + kGood1Url2)));
   1237   EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
   1238       GURL(std::string("http://") + kGood1Url2 + "/c.html")));
   1239 
   1240   EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
   1241       GURL(std::string("https://") + kGood1Url2 + "/c.html")));
   1242 
   1243   EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
   1244       GURL(std::string("http://") + kGood2Url1 + "/c")));
   1245   EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
   1246       GURL(std::string("http://") + kGood2Url1 + "/c?bla")));
   1247   EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
   1248       GURL(std::string("http://") + kGood2Url1 + "/c/bla")));
   1249 
   1250   EXPECT_FALSE(database_->ContainsCsdWhitelistedUrl(
   1251       GURL(std::string("http://www.google.com/"))));
   1252 
   1253   EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl(
   1254       GURL(std::string("http://") + kGood2Url1 + "/c")));
   1255   EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl(
   1256       GURL(std::string("http://") + kGood2Url1 + "/c?bla")));
   1257   EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl(
   1258       GURL(std::string("http://") + kGood2Url1 + "/c/bla")));
   1259 
   1260   EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl(
   1261       GURL(std::string("http://good3.com/a/b/c/d/e/f/g/"))));
   1262   EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl(
   1263       GURL(std::string("http://a.b.good3.com/"))));
   1264 
   1265   EXPECT_FALSE(database_->ContainsDownloadWhitelistedString("asdf"));
   1266   EXPECT_TRUE(database_->ContainsDownloadWhitelistedString(kGoodString));
   1267 
   1268   EXPECT_FALSE(database_->ContainsDownloadWhitelistedUrl(
   1269       GURL(std::string("http://www.google.com/"))));
   1270 
   1271   // The CSD whitelist killswitch is not present.
   1272   EXPECT_FALSE(database_->IsCsdWhitelistKillSwitchOn());
   1273 
   1274   // Test only add the malware IP killswitch
   1275   csd_chunks.clear();
   1276   csd_chunks.push_back(AddChunkFullHashValue(
   1277       15, "sb-ssl.google.com/safebrowsing/csd/killswitch_malware"));
   1278 
   1279   ASSERT_TRUE(database_->UpdateStarted(&lists));
   1280   database_->InsertChunks(safe_browsing_util::kCsdWhiteList, csd_chunks.get());
   1281   database_->UpdateFinished(true);
   1282 
   1283   EXPECT_TRUE(database_->IsMalwareIPMatchKillSwitchOn());
   1284   // The CSD whitelist killswitch is not present.
   1285   EXPECT_FALSE(database_->IsCsdWhitelistKillSwitchOn());
   1286 
   1287   // Test that the kill-switch works as intended.
   1288   csd_chunks.clear();
   1289   download_chunks.clear();
   1290   lists.clear();
   1291   csd_chunks.push_back(AddChunkFullHashValue(
   1292       5, "sb-ssl.google.com/safebrowsing/csd/killswitch"));
   1293   download_chunks.push_back(AddChunkFullHashValue(
   1294       5, "sb-ssl.google.com/safebrowsing/csd/killswitch"));
   1295 
   1296   ASSERT_TRUE(database_->UpdateStarted(&lists));
   1297   database_->InsertChunks(safe_browsing_util::kCsdWhiteList, csd_chunks.get());
   1298   database_->InsertChunks(safe_browsing_util::kDownloadWhiteList,
   1299                           download_chunks.get());
   1300   database_->UpdateFinished(true);
   1301 
   1302   // The CSD whitelist killswitch is present.
   1303   EXPECT_TRUE(database_->IsCsdWhitelistKillSwitchOn());
   1304   EXPECT_TRUE(database_->IsMalwareIPMatchKillSwitchOn());
   1305   EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
   1306       GURL(std::string("https://") + kGood1Url2 + "/c.html")));
   1307   EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
   1308       GURL(std::string("http://www.google.com/"))));
   1309   EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
   1310       GURL(std::string("http://www.phishing_url.com/"))));
   1311 
   1312   EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl(
   1313       GURL(std::string("https://") + kGood1Url2 + "/c.html")));
   1314   EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl(
   1315       GURL(std::string("http://www.google.com/"))));
   1316   EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl(
   1317       GURL(std::string("http://www.phishing_url.com/"))));
   1318 
   1319   EXPECT_TRUE(database_->ContainsDownloadWhitelistedString("asdf"));
   1320   EXPECT_TRUE(database_->ContainsDownloadWhitelistedString(kGoodString));
   1321 
   1322   // Remove the kill-switch and verify that we can recover.
   1323   csd_chunks.clear();
   1324   download_chunks.clear();
   1325   lists.clear();
   1326   csd_chunks.push_back(SubChunkFullHashValue(
   1327       1, "sb-ssl.google.com/safebrowsing/csd/killswitch", 5));
   1328   csd_chunks.push_back(SubChunkFullHashValue(
   1329       10, "sb-ssl.google.com/safebrowsing/csd/killswitch_malware", 15));
   1330   download_chunks.push_back(SubChunkFullHashValue(
   1331       1, "sb-ssl.google.com/safebrowsing/csd/killswitch", 5));
   1332 
   1333   ASSERT_TRUE(database_->UpdateStarted(&lists));
   1334   database_->InsertChunks(safe_browsing_util::kCsdWhiteList, csd_chunks.get());
   1335   database_->InsertChunks(safe_browsing_util::kDownloadWhiteList,
   1336                           download_chunks.get());
   1337   database_->UpdateFinished(true);
   1338 
   1339   EXPECT_FALSE(database_->IsMalwareIPMatchKillSwitchOn());
   1340   EXPECT_FALSE(database_->IsCsdWhitelistKillSwitchOn());
   1341   EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
   1342       GURL(std::string("https://") + kGood1Url2 + "/c.html")));
   1343   EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
   1344       GURL(std::string("https://") + kGood2Url1 + "/c/bla")));
   1345   EXPECT_FALSE(database_->ContainsCsdWhitelistedUrl(
   1346       GURL(std::string("http://www.google.com/"))));
   1347   EXPECT_FALSE(database_->ContainsCsdWhitelistedUrl(
   1348       GURL(std::string("http://www.phishing_url.com/"))));
   1349 
   1350   EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl(
   1351       GURL(std::string("https://") + kGood2Url1 + "/c/bla")));
   1352   EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl(
   1353       GURL(std::string("https://good3.com/"))));
   1354   EXPECT_TRUE(database_->ContainsDownloadWhitelistedString(kGoodString));
   1355   EXPECT_FALSE(database_->ContainsDownloadWhitelistedUrl(
   1356       GURL(std::string("http://www.google.com/"))));
   1357   EXPECT_FALSE(database_->ContainsDownloadWhitelistedUrl(
   1358       GURL(std::string("http://www.phishing_url.com/"))));
   1359   EXPECT_FALSE(database_->ContainsDownloadWhitelistedString("asdf"));
   1360 
   1361   database_.reset();
   1362 }
   1363 
   1364 // Test to make sure we could insert chunk list that
   1365 // contains entries for the same host.
   1366 TEST_F(SafeBrowsingDatabaseTest, SameHostEntriesOkay) {
   1367   ScopedVector<SBChunkData> chunks;
   1368 
   1369   // Add a malware add chunk with two entries of the same host.
   1370   chunks.push_back(AddChunkPrefix2Value(1,
   1371                                         "www.evil.com/malware1.html",
   1372                                         "www.evil.com/malware2.html"));
   1373 
   1374   // Insert the testing chunks into database.
   1375   std::vector<SBListChunkRanges> lists;
   1376   ASSERT_TRUE(database_->UpdateStarted(&lists));
   1377   database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
   1378   database_->UpdateFinished(true);
   1379 
   1380   GetListsInfo(&lists);
   1381   ASSERT_LE(1U, lists.size());
   1382   EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
   1383   EXPECT_EQ("1", lists[0].adds);
   1384   EXPECT_TRUE(lists[0].subs.empty());
   1385 
   1386   // Add a phishing add chunk with two entries of the same host.
   1387   chunks.clear();
   1388   chunks.push_back(AddChunkPrefix2Value(47,
   1389                                         "www.evil.com/phishing1.html",
   1390                                         "www.evil.com/phishing2.html"));
   1391 
   1392   ASSERT_TRUE(database_->UpdateStarted(&lists));
   1393   database_->InsertChunks(safe_browsing_util::kPhishingList, chunks.get());
   1394   database_->UpdateFinished(true);
   1395 
   1396   GetListsInfo(&lists);
   1397   ASSERT_EQ(2U, lists.size());
   1398   EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
   1399   EXPECT_EQ("1", lists[0].adds);
   1400   EXPECT_TRUE(lists[0].subs.empty());
   1401   EXPECT_EQ(safe_browsing_util::kPhishingList, lists[1].name);
   1402   EXPECT_EQ("47", lists[1].adds);
   1403   EXPECT_TRUE(lists[1].subs.empty());
   1404 
   1405   std::vector<SBPrefix> prefix_hits;
   1406   std::vector<SBFullHashResult> cache_hits;
   1407 
   1408   EXPECT_TRUE(database_->ContainsBrowseUrl(
   1409       GURL("http://www.evil.com/malware1.html"), &prefix_hits, &cache_hits));
   1410   EXPECT_TRUE(database_->ContainsBrowseUrl(
   1411       GURL("http://www.evil.com/malware2.html"), &prefix_hits, &cache_hits));
   1412   EXPECT_TRUE(database_->ContainsBrowseUrl(
   1413       GURL("http://www.evil.com/phishing1.html"), &prefix_hits, &cache_hits));
   1414   EXPECT_TRUE(database_->ContainsBrowseUrl(
   1415       GURL("http://www.evil.com/phishing2.html"), &prefix_hits, &cache_hits));
   1416 
   1417   // Test removing a single prefix from the add chunk.
   1418   // Remove the prefix that added first.
   1419   chunks.clear();
   1420   chunks.push_back(SubChunkPrefixValue(4, "www.evil.com/malware1.html", 1));
   1421   ASSERT_TRUE(database_->UpdateStarted(&lists));
   1422   database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
   1423   database_->UpdateFinished(true);
   1424 
   1425   // Remove the prefix that added last.
   1426   chunks.clear();
   1427   chunks.push_back(SubChunkPrefixValue(5, "www.evil.com/phishing2.html", 47));
   1428   ASSERT_TRUE(database_->UpdateStarted(&lists));
   1429   database_->InsertChunks(safe_browsing_util::kPhishingList, chunks.get());
   1430   database_->UpdateFinished(true);
   1431 
   1432   // Verify that the database contains urls expected.
   1433   EXPECT_FALSE(database_->ContainsBrowseUrl(
   1434       GURL("http://www.evil.com/malware1.html"), &prefix_hits, &cache_hits));
   1435   EXPECT_TRUE(database_->ContainsBrowseUrl(
   1436       GURL("http://www.evil.com/malware2.html"), &prefix_hits, &cache_hits));
   1437   EXPECT_TRUE(database_->ContainsBrowseUrl(
   1438       GURL("http://www.evil.com/phishing1.html"), &prefix_hits, &cache_hits));
   1439   EXPECT_FALSE(database_->ContainsBrowseUrl(
   1440       GURL("http://www.evil.com/phishing2.html"), &prefix_hits, &cache_hits));
   1441 }
   1442 
   1443 // Test that an empty update doesn't actually update the database.
   1444 // This isn't a functionality requirement, but it is a useful
   1445 // optimization.
   1446 TEST_F(SafeBrowsingDatabaseTest, EmptyUpdate) {
   1447   ScopedVector<SBChunkData> chunks;
   1448 
   1449   base::FilePath filename = database_->BrowseDBFilename(database_filename_);
   1450 
   1451   // Prime the database.
   1452   std::vector<SBListChunkRanges> lists;
   1453   ASSERT_TRUE(database_->UpdateStarted(&lists));
   1454   chunks.push_back(AddChunkPrefixValue(1, "www.evil.com/malware.html"));
   1455   database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
   1456   database_->UpdateFinished(true);
   1457 
   1458   // Get an older time to reset the lastmod time for detecting whether
   1459   // the file has been updated.
   1460   base::File::Info before_info, after_info;
   1461   ASSERT_TRUE(base::GetFileInfo(filename, &before_info));
   1462   const Time old_last_modified =
   1463       before_info.last_modified - TimeDelta::FromSeconds(10);
   1464 
   1465   // Inserting another chunk updates the database file.  The sleep is
   1466   // needed because otherwise the entire test can finish w/in the
   1467   // resolution of the lastmod time.
   1468   ASSERT_TRUE(base::TouchFile(filename, old_last_modified, old_last_modified));
   1469   ASSERT_TRUE(base::GetFileInfo(filename, &before_info));
   1470   ASSERT_TRUE(database_->UpdateStarted(&lists));
   1471   chunks.push_back(AddChunkPrefixValue(2, "www.foo.com/malware.html"));
   1472   database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
   1473   database_->UpdateFinished(true);
   1474   ASSERT_TRUE(base::GetFileInfo(filename, &after_info));
   1475   EXPECT_LT(before_info.last_modified, after_info.last_modified);
   1476 
   1477   // Deleting a chunk updates the database file.
   1478   ASSERT_TRUE(base::TouchFile(filename, old_last_modified, old_last_modified));
   1479   ASSERT_TRUE(base::GetFileInfo(filename, &before_info));
   1480   ASSERT_TRUE(database_->UpdateStarted(&lists));
   1481   AddDelChunk(safe_browsing_util::kMalwareList, 2);
   1482   database_->UpdateFinished(true);
   1483   ASSERT_TRUE(base::GetFileInfo(filename, &after_info));
   1484   EXPECT_LT(before_info.last_modified, after_info.last_modified);
   1485 
   1486   // Simply calling |UpdateStarted()| then |UpdateFinished()| does not
   1487   // update the database file.
   1488   ASSERT_TRUE(base::TouchFile(filename, old_last_modified, old_last_modified));
   1489   ASSERT_TRUE(base::GetFileInfo(filename, &before_info));
   1490   ASSERT_TRUE(database_->UpdateStarted(&lists));
   1491   database_->UpdateFinished(true);
   1492   ASSERT_TRUE(base::GetFileInfo(filename, &after_info));
   1493   EXPECT_EQ(before_info.last_modified, after_info.last_modified);
   1494 }
   1495 
   1496 // Test that a filter file is written out during update and read back
   1497 // in during setup.
   1498 TEST_F(SafeBrowsingDatabaseTest, FilterFile) {
   1499   // Create a database with trivial example data and write it out.
   1500   {
   1501     // Prime the database.
   1502     std::vector<SBListChunkRanges> lists;
   1503     ASSERT_TRUE(database_->UpdateStarted(&lists));
   1504 
   1505     ScopedVector<SBChunkData> chunks;
   1506     chunks.push_back(AddChunkPrefixValue(1, "www.evil.com/malware.html"));
   1507     database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
   1508     database_->UpdateFinished(true);
   1509   }
   1510 
   1511   // Find the malware url in the database, don't find a good url.
   1512   std::vector<SBPrefix> prefix_hits;
   1513   std::vector<SBFullHashResult> cache_hits;
   1514   EXPECT_TRUE(database_->ContainsBrowseUrl(
   1515       GURL("http://www.evil.com/malware.html"), &prefix_hits, &cache_hits));
   1516   EXPECT_FALSE(database_->ContainsBrowseUrl(
   1517       GURL("http://www.good.com/goodware.html"), &prefix_hits, &cache_hits));
   1518 
   1519   base::FilePath filter_file = database_->PrefixSetForFilename(
   1520       database_->BrowseDBFilename(database_filename_));
   1521 
   1522   // After re-creating the database, it should have a filter read from
   1523   // a file, so it should find the same results.
   1524   ASSERT_TRUE(base::PathExists(filter_file));
   1525   database_.reset(new SafeBrowsingDatabaseNew);
   1526   database_->Init(database_filename_);
   1527   EXPECT_TRUE(database_->ContainsBrowseUrl(
   1528       GURL("http://www.evil.com/malware.html"), &prefix_hits, &cache_hits));
   1529   EXPECT_FALSE(database_->ContainsBrowseUrl(
   1530       GURL("http://www.good.com/goodware.html"), &prefix_hits, &cache_hits));
   1531 
   1532   // If there is no filter file, the database cannot find malware urls.
   1533   base::DeleteFile(filter_file, false);
   1534   ASSERT_FALSE(base::PathExists(filter_file));
   1535   database_.reset(new SafeBrowsingDatabaseNew);
   1536   database_->Init(database_filename_);
   1537   EXPECT_FALSE(database_->ContainsBrowseUrl(
   1538       GURL("http://www.evil.com/malware.html"), &prefix_hits, &cache_hits));
   1539   EXPECT_FALSE(database_->ContainsBrowseUrl(
   1540       GURL("http://www.good.com/goodware.html"), &prefix_hits, &cache_hits));
   1541 }
   1542 
   1543 TEST_F(SafeBrowsingDatabaseTest, MalwareIpBlacklist) {
   1544   database_.reset();
   1545   SafeBrowsingStoreFile* browse_store = new SafeBrowsingStoreFile();
   1546   SafeBrowsingStoreFile* ip_blacklist_store = new SafeBrowsingStoreFile();
   1547   database_.reset(new SafeBrowsingDatabaseNew(browse_store,
   1548                                               NULL,
   1549                                               NULL,
   1550                                               NULL,
   1551                                               NULL,
   1552                                               NULL,
   1553                                               ip_blacklist_store));
   1554   database_->Init(database_filename_);
   1555   std::vector<SBListChunkRanges> lists;
   1556   ASSERT_TRUE(database_->UpdateStarted(&lists));
   1557 
   1558   ScopedVector<SBChunkData> chunks;
   1559 
   1560   // IPv4 prefix match for ::ffff:192.168.1.0/120.
   1561   chunks.push_back(AddChunkHashedIpValue(1, "::ffff:192.168.1.0", 120));
   1562 
   1563   // IPv4 exact match for ::ffff:192.1.1.1.
   1564   chunks.push_back(AddChunkHashedIpValue(2, "::ffff:192.1.1.1", 128));
   1565 
   1566   // IPv6 exact match for: fe80::31a:a0ff:fe10:786e/128.
   1567   chunks.push_back(AddChunkHashedIpValue(3, "fe80::31a:a0ff:fe10:786e", 128));
   1568 
   1569   // IPv6 prefix match for: 2620:0:1000:3103::/64.
   1570   chunks.push_back(AddChunkHashedIpValue(4, "2620:0:1000:3103::", 64));
   1571 
   1572   // IPv4 prefix match for ::ffff:192.1.122.0/119.
   1573   chunks.push_back(AddChunkHashedIpValue(5, "::ffff:192.1.122.0", 119));
   1574 
   1575   // IPv4 prefix match for ::ffff:192.1.128.0/113.
   1576   chunks.push_back(AddChunkHashedIpValue(6, "::ffff:192.1.128.0", 113));
   1577 
   1578   database_->InsertChunks(safe_browsing_util::kIPBlacklist, chunks.get());
   1579   database_->UpdateFinished(true);
   1580 
   1581   EXPECT_FALSE(database_->ContainsMalwareIP("192.168.0.255"));
   1582   EXPECT_TRUE(database_->ContainsMalwareIP("192.168.1.0"));
   1583   EXPECT_TRUE(database_->ContainsMalwareIP("192.168.1.255"));
   1584   EXPECT_TRUE(database_->ContainsMalwareIP("192.168.1.10"));
   1585   EXPECT_TRUE(database_->ContainsMalwareIP("::ffff:192.168.1.2"));
   1586   EXPECT_FALSE(database_->ContainsMalwareIP("192.168.2.0"));
   1587 
   1588   EXPECT_FALSE(database_->ContainsMalwareIP("192.1.1.0"));
   1589   EXPECT_TRUE(database_->ContainsMalwareIP("192.1.1.1"));
   1590   EXPECT_FALSE(database_->ContainsMalwareIP("192.1.1.2"));
   1591 
   1592   EXPECT_FALSE(database_->ContainsMalwareIP(
   1593       "2620:0:1000:3102:ffff:ffff:ffff:ffff"));
   1594   EXPECT_TRUE(database_->ContainsMalwareIP("2620:0:1000:3103::"));
   1595   EXPECT_TRUE(database_->ContainsMalwareIP(
   1596       "2620:0:1000:3103:ffff:ffff:ffff:ffff"));
   1597   EXPECT_FALSE(database_->ContainsMalwareIP("2620:0:1000:3104::"));
   1598 
   1599   EXPECT_FALSE(database_->ContainsMalwareIP("fe80::21a:a0ff:fe10:786d"));
   1600   EXPECT_TRUE(database_->ContainsMalwareIP("fe80::31a:a0ff:fe10:786e"));
   1601   EXPECT_FALSE(database_->ContainsMalwareIP("fe80::21a:a0ff:fe10:786f"));
   1602 
   1603   EXPECT_FALSE(database_->ContainsMalwareIP("192.1.121.255"));
   1604   EXPECT_TRUE(database_->ContainsMalwareIP("192.1.122.0"));
   1605   EXPECT_TRUE(database_->ContainsMalwareIP("::ffff:192.1.122.1"));
   1606   EXPECT_TRUE(database_->ContainsMalwareIP("192.1.122.255"));
   1607   EXPECT_TRUE(database_->ContainsMalwareIP("192.1.123.0"));
   1608   EXPECT_TRUE(database_->ContainsMalwareIP("192.1.123.255"));
   1609   EXPECT_FALSE(database_->ContainsMalwareIP("192.1.124.0"));
   1610 
   1611   EXPECT_FALSE(database_->ContainsMalwareIP("192.1.127.255"));
   1612   EXPECT_TRUE(database_->ContainsMalwareIP("192.1.128.0"));
   1613   EXPECT_TRUE(database_->ContainsMalwareIP("::ffff:192.1.128.1"));
   1614   EXPECT_TRUE(database_->ContainsMalwareIP("192.1.128.255"));
   1615   EXPECT_TRUE(database_->ContainsMalwareIP("192.1.255.0"));
   1616   EXPECT_TRUE(database_->ContainsMalwareIP("192.1.255.255"));
   1617   EXPECT_FALSE(database_->ContainsMalwareIP("192.2.0.0"));
   1618 }
   1619 
   1620 TEST_F(SafeBrowsingDatabaseTest, ContainsBrowseURL) {
   1621   std::vector<SBListChunkRanges> lists;
   1622   ASSERT_TRUE(database_->UpdateStarted(&lists));
   1623 
   1624   // Add a host-level hit.
   1625   {
   1626     ScopedVector<SBChunkData> chunks;
   1627     chunks.push_back(AddChunkPrefixValue(1, "www.evil.com/"));
   1628     database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
   1629   }
   1630 
   1631   // Add a specific fullhash.
   1632   static const char kWhateverMalware[] = "www.whatever.com/malware.html";
   1633   {
   1634     ScopedVector<SBChunkData> chunks;
   1635     chunks.push_back(AddChunkFullHashValue(2, kWhateverMalware));
   1636     database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
   1637   }
   1638 
   1639   // Add a fullhash which has a prefix collision for a known url.
   1640   static const char kExampleFine[] = "www.example.com/fine.html";
   1641   static const char kExampleCollision[] =
   1642       "www.example.com/3123364814/malware.htm";
   1643   ASSERT_EQ(SBPrefixForString(kExampleFine),
   1644             SBPrefixForString(kExampleCollision));
   1645   {
   1646     ScopedVector<SBChunkData> chunks;
   1647     chunks.push_back(AddChunkFullHashValue(3, kExampleCollision));
   1648     database_->InsertChunks(safe_browsing_util::kMalwareList, chunks.get());
   1649   }
   1650 
   1651   database_->UpdateFinished(true);
   1652 
   1653   std::vector<SBPrefix> prefix_hits;
   1654   std::vector<SBFullHashResult> cache_hits;
   1655 
   1656   // Anything will hit the host prefix.
   1657   EXPECT_TRUE(database_->ContainsBrowseUrl(
   1658       GURL("http://www.evil.com/malware.html"), &prefix_hits, &cache_hits));
   1659   ASSERT_EQ(1U, prefix_hits.size());
   1660   EXPECT_EQ(SBPrefixForString("www.evil.com/"), prefix_hits[0]);
   1661   EXPECT_TRUE(cache_hits.empty());
   1662 
   1663   // Hit the specific URL prefix.
   1664   EXPECT_TRUE(database_->ContainsBrowseUrl(
   1665       GURL(std::string("http://") + kWhateverMalware),
   1666       &prefix_hits, &cache_hits));
   1667   ASSERT_EQ(1U, prefix_hits.size());
   1668   EXPECT_EQ(SBPrefixForString(kWhateverMalware), prefix_hits[0]);
   1669   EXPECT_TRUE(cache_hits.empty());
   1670 
   1671   // Other URLs at that host are fine.
   1672   EXPECT_FALSE(database_->ContainsBrowseUrl(
   1673       GURL("http://www.whatever.com/fine.html"), &prefix_hits, &cache_hits));
   1674   EXPECT_TRUE(prefix_hits.empty());
   1675   EXPECT_TRUE(cache_hits.empty());
   1676 
   1677   // Hit the specific URL full hash.
   1678   EXPECT_TRUE(database_->ContainsBrowseUrl(
   1679       GURL(std::string("http://") + kExampleCollision),
   1680       &prefix_hits, &cache_hits));
   1681   ASSERT_EQ(1U, prefix_hits.size());
   1682   EXPECT_EQ(SBPrefixForString(kExampleCollision), prefix_hits[0]);
   1683   EXPECT_TRUE(cache_hits.empty());
   1684 
   1685   // This prefix collides, but no full hash match.
   1686   EXPECT_FALSE(database_->ContainsBrowseUrl(
   1687       GURL(std::string("http://") + kExampleFine), &prefix_hits, &cache_hits));
   1688 }
   1689