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