[Metrics] Make MetricsStateManager take a callback param to check if UMA is enabled.
[chromium-blink-merge.git] / chrome / browser / safe_browsing / safe_browsing_database_unittest.cc
blob8e165c82eab27d2b1028c8e9af7c3a3a27decdd4
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.
7 #include "base/file_util.h"
8 #include "base/files/scoped_temp_dir.h"
9 #include "base/logging.h"
10 #include "base/message_loop/message_loop.h"
11 #include "base/sha1.h"
12 #include "base/time/time.h"
13 #include "chrome/browser/safe_browsing/safe_browsing_database.h"
14 #include "chrome/browser/safe_browsing/safe_browsing_store_file.h"
15 #include "content/public/test/test_browser_thread_bundle.h"
16 #include "crypto/sha2.h"
17 #include "net/base/net_util.h"
18 #include "sql/connection.h"
19 #include "sql/statement.h"
20 #include "testing/gtest/include/gtest/gtest.h"
21 #include "testing/platform_test.h"
22 #include "url/gurl.h"
24 using base::Time;
25 using base::TimeDelta;
27 namespace {
29 const TimeDelta kCacheLifetime = TimeDelta::FromMinutes(45);
31 SBPrefix SBPrefixForString(const std::string& str) {
32 return SBFullHashForString(str).prefix;
35 std::string HashedIpPrefix(const std::string& ip_prefix, size_t prefix_size) {
36 net::IPAddressNumber ip_number;
37 EXPECT_TRUE(net::ParseIPLiteralToNumber(ip_prefix, &ip_number));
38 EXPECT_EQ(net::kIPv6AddressSize, ip_number.size());
39 const std::string hashed_ip_prefix = base::SHA1HashString(
40 net::IPAddressToPackedString(ip_number));
41 std::string hash(crypto::kSHA256Length, '\0');
42 hash.replace(0, hashed_ip_prefix.size(), hashed_ip_prefix);
43 hash[base::kSHA1Length] = static_cast<char>(prefix_size);
44 return hash;
47 // Add a host-level entry.
48 void InsertAddChunkHostPrefix(SBChunk* chunk,
49 int chunk_number,
50 const std::string& host_name) {
51 chunk->chunk_number = chunk_number;
52 chunk->is_add = true;
53 SBChunkHost host;
54 host.host = SBPrefixForString(host_name);
55 host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 0);
56 host.entry->set_chunk_id(chunk->chunk_number);
57 chunk->hosts.push_back(host);
60 // Same as InsertAddChunkHostPrefixUrl, but with pre-computed
61 // prefix values.
62 void InsertAddChunkHostPrefixValue(SBChunk* chunk,
63 int chunk_number,
64 const SBPrefix& host_prefix,
65 const SBPrefix& url_prefix) {
66 chunk->chunk_number = chunk_number;
67 chunk->is_add = true;
68 SBChunkHost host;
69 host.host = host_prefix;
70 host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 1);
71 host.entry->set_chunk_id(chunk->chunk_number);
72 host.entry->SetPrefixAt(0, url_prefix);
73 chunk->hosts.push_back(host);
76 // A helper function that appends one AddChunkHost to chunk with
77 // one url for prefix.
78 void InsertAddChunkHostPrefixUrl(SBChunk* chunk,
79 int chunk_number,
80 const std::string& host_name,
81 const std::string& url) {
82 InsertAddChunkHostPrefixValue(chunk, chunk_number,
83 SBPrefixForString(host_name),
84 SBPrefixForString(url));
87 // Same as InsertAddChunkHostPrefixUrl, but with full hashes.
88 void InsertAddChunkHostFullHashes(SBChunk* chunk,
89 int chunk_number,
90 const std::string& host_name,
91 const std::string& url) {
92 chunk->chunk_number = chunk_number;
93 chunk->is_add = true;
94 SBChunkHost host;
95 host.host = SBPrefixForString(host_name);
96 host.entry = SBEntry::Create(SBEntry::ADD_FULL_HASH, 1);
97 host.entry->set_chunk_id(chunk->chunk_number);
98 host.entry->SetFullHashAt(0, SBFullHashForString(url));
99 chunk->hosts.push_back(host);
102 // TODO(shess): This sounds like something to insert a full-hash chunk, but it's
103 // actually specific to IP blacklist.
104 void InsertAddChunkFullHash(SBChunk* chunk,
105 int chunk_number,
106 const std::string& ip_str,
107 size_t prefix_size) {
108 const std::string full_hash_str = HashedIpPrefix(ip_str, prefix_size);
109 EXPECT_EQ(sizeof(SBFullHash), full_hash_str.size());
110 SBFullHash full_hash;
111 std::memcpy(&(full_hash.full_hash), full_hash_str.data(), sizeof(SBFullHash));
113 chunk->chunk_number = chunk_number;
114 chunk->is_add = true;
115 SBChunkHost host;
116 host.host = full_hash.prefix;
117 host.entry = SBEntry::Create(SBEntry::ADD_FULL_HASH, 1);
118 host.entry->set_chunk_id(chunk->chunk_number);
119 host.entry->SetFullHashAt(0, full_hash);
120 chunk->hosts.push_back(host);
123 // Same as InsertAddChunkHostPrefixUrl, but with two urls for prefixes.
124 void InsertAddChunkHost2PrefixUrls(SBChunk* chunk,
125 int chunk_number,
126 const std::string& host_name,
127 const std::string& url1,
128 const std::string& url2) {
129 chunk->chunk_number = chunk_number;
130 chunk->is_add = true;
131 SBChunkHost host;
132 host.host = SBPrefixForString(host_name);
133 host.entry = SBEntry::Create(SBEntry::ADD_PREFIX, 2);
134 host.entry->set_chunk_id(chunk->chunk_number);
135 host.entry->SetPrefixAt(0, SBPrefixForString(url1));
136 host.entry->SetPrefixAt(1, SBPrefixForString(url2));
137 chunk->hosts.push_back(host);
140 // Same as InsertAddChunkHost2PrefixUrls, but with full hashes.
141 void InsertAddChunkHost2FullHashes(SBChunk* chunk,
142 int chunk_number,
143 const std::string& host_name,
144 const std::string& url1,
145 const std::string& url2) {
146 chunk->chunk_number = chunk_number;
147 chunk->is_add = true;
148 SBChunkHost host;
149 host.host = SBPrefixForString(host_name);
150 host.entry = SBEntry::Create(SBEntry::ADD_FULL_HASH, 2);
151 host.entry->set_chunk_id(chunk->chunk_number);
152 host.entry->SetFullHashAt(0, SBFullHashForString(url1));
153 host.entry->SetFullHashAt(1, SBFullHashForString(url2));
154 chunk->hosts.push_back(host);
157 // Same as InsertSubChunkHostPrefixUrl, but with pre-computed
158 // prefix values.
159 void InsertSubChunkHostPrefixValue(SBChunk* chunk,
160 int chunk_number,
161 int chunk_id_to_sub,
162 const SBPrefix& host_prefix,
163 const SBPrefix& url_prefix) {
164 chunk->chunk_number = chunk_number;
165 chunk->is_add = false;
166 SBChunkHost host;
167 host.host = host_prefix;
168 host.entry = SBEntry::Create(SBEntry::SUB_PREFIX, 1);
169 host.entry->set_chunk_id(chunk->chunk_number);
170 host.entry->SetChunkIdAtPrefix(0, chunk_id_to_sub);
171 host.entry->SetPrefixAt(0, url_prefix);
172 chunk->hosts.push_back(host);
175 // A helper function that adds one SubChunkHost to chunk with
176 // one url for prefix.
177 void InsertSubChunkHostPrefixUrl(SBChunk* chunk,
178 int chunk_number,
179 int chunk_id_to_sub,
180 const std::string& host_name,
181 const std::string& url) {
182 InsertSubChunkHostPrefixValue(chunk, chunk_number,
183 chunk_id_to_sub,
184 SBPrefixForString(host_name),
185 SBPrefixForString(url));
188 // Same as InsertSubChunkHostPrefixUrl, but with two urls for prefixes.
189 void InsertSubChunkHost2PrefixUrls(SBChunk* chunk,
190 int chunk_number,
191 int chunk_id_to_sub,
192 const std::string& host_name,
193 const std::string& url1,
194 const std::string& url2) {
195 chunk->chunk_number = chunk_number;
196 chunk->is_add = false;
197 SBChunkHost host;
198 host.host = SBPrefixForString(host_name);
199 host.entry = SBEntry::Create(SBEntry::SUB_PREFIX, 2);
200 host.entry->set_chunk_id(chunk->chunk_number);
201 host.entry->SetPrefixAt(0, SBPrefixForString(url1));
202 host.entry->SetChunkIdAtPrefix(0, chunk_id_to_sub);
203 host.entry->SetPrefixAt(1, SBPrefixForString(url2));
204 host.entry->SetChunkIdAtPrefix(1, chunk_id_to_sub);
205 chunk->hosts.push_back(host);
208 // Same as InsertSubChunkHost2PrefixUrls, but with full hashes.
209 void InsertSubChunkHostFullHash(SBChunk* chunk,
210 int chunk_number,
211 int chunk_id_to_sub,
212 const std::string& host_name,
213 const std::string& url) {
214 chunk->chunk_number = chunk_number;
215 chunk->is_add = false;
216 SBChunkHost host;
217 host.host = SBPrefixForString(host_name);
218 host.entry = SBEntry::Create(SBEntry::SUB_FULL_HASH, 2);
219 host.entry->set_chunk_id(chunk->chunk_number);
220 host.entry->SetFullHashAt(0, SBFullHashForString(url));
221 host.entry->SetChunkIdAtPrefix(0, chunk_id_to_sub);
222 chunk->hosts.push_back(host);
225 // Prevent DCHECK from killing tests.
226 // TODO(shess): Pawel disputes the use of this, so the test which uses
227 // it is DISABLED. http://crbug.com/56448
228 class ScopedLogMessageIgnorer {
229 public:
230 ScopedLogMessageIgnorer() {
231 logging::SetLogMessageHandler(&LogMessageIgnorer);
233 ~ScopedLogMessageIgnorer() {
234 // TODO(shess): Would be better to verify whether anyone else
235 // changed it, and then restore it to the previous value.
236 logging::SetLogMessageHandler(NULL);
239 private:
240 static bool LogMessageIgnorer(int severity, const char* file, int line,
241 size_t message_start, const std::string& str) {
242 // Intercept FATAL, strip the stack backtrace, and log it without
243 // the crash part.
244 if (severity == logging::LOG_FATAL) {
245 size_t newline = str.find('\n');
246 if (newline != std::string::npos) {
247 const std::string msg = str.substr(0, newline + 1);
248 fprintf(stderr, "%s", msg.c_str());
249 fflush(stderr);
251 return true;
254 return false;
258 } // namespace
260 class SafeBrowsingDatabaseTest : public PlatformTest {
261 public:
262 virtual void SetUp() {
263 PlatformTest::SetUp();
265 // Setup a database in a temporary directory.
266 ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
267 database_.reset(new SafeBrowsingDatabaseNew);
268 database_filename_ =
269 temp_dir_.path().AppendASCII("SafeBrowsingTestDatabase");
270 database_->Init(database_filename_);
273 virtual void TearDown() {
274 database_.reset();
276 PlatformTest::TearDown();
279 void GetListsInfo(std::vector<SBListChunkRanges>* lists) {
280 lists->clear();
281 ASSERT_TRUE(database_->UpdateStarted(lists));
282 database_->UpdateFinished(true);
285 // Helper function to do an AddDel or SubDel command.
286 void DelChunk(const std::string& list,
287 int chunk_id,
288 bool is_sub_del) {
289 std::vector<SBChunkDelete> deletes;
290 SBChunkDelete chunk_delete;
291 chunk_delete.list_name = list;
292 chunk_delete.is_sub_del = is_sub_del;
293 chunk_delete.chunk_del.push_back(ChunkRange(chunk_id));
294 deletes.push_back(chunk_delete);
295 database_->DeleteChunks(deletes);
298 void AddDelChunk(const std::string& list, int chunk_id) {
299 DelChunk(list, chunk_id, false);
302 void SubDelChunk(const std::string& list, int chunk_id) {
303 DelChunk(list, chunk_id, true);
306 // Utility function for setting up the database for the caching test.
307 void PopulateDatabaseForCacheTest();
309 scoped_ptr<SafeBrowsingDatabaseNew> database_;
310 base::FilePath database_filename_;
311 base::ScopedTempDir temp_dir_;
314 // Tests retrieving list name information.
315 TEST_F(SafeBrowsingDatabaseTest, ListNameForBrowse) {
316 SBChunkList chunks;
317 SBChunk chunk;
319 InsertAddChunkHostPrefixUrl(&chunk, 1, "www.evil.com/",
320 "www.evil.com/malware.html");
321 chunks.clear();
322 chunks.push_back(chunk);
323 std::vector<SBListChunkRanges> lists;
324 ASSERT_TRUE(database_->UpdateStarted(&lists));
325 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
327 chunk.hosts.clear();
328 InsertAddChunkHostPrefixUrl(&chunk, 2, "www.foo.com/",
329 "www.foo.com/malware.html");
330 chunks.clear();
331 chunks.push_back(chunk);
332 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
334 chunk.hosts.clear();
335 InsertAddChunkHostPrefixUrl(&chunk, 3, "www.whatever.com/",
336 "www.whatever.com/malware.html");
337 chunks.clear();
338 chunks.push_back(chunk);
339 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
340 database_->UpdateFinished(true);
342 GetListsInfo(&lists);
343 ASSERT_LE(1U, lists.size());
344 EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
345 EXPECT_EQ("1-3", lists[0].adds);
346 EXPECT_TRUE(lists[0].subs.empty());
348 // Insert a malware sub chunk.
349 chunk.hosts.clear();
350 InsertSubChunkHostPrefixUrl(&chunk, 7, 19, "www.subbed.com/",
351 "www.subbed.com/noteveil1.html");
352 chunks.clear();
353 chunks.push_back(chunk);
355 ASSERT_TRUE(database_->UpdateStarted(&lists));
356 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
357 database_->UpdateFinished(true);
359 GetListsInfo(&lists);
360 ASSERT_LE(1U, lists.size());
361 EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
362 EXPECT_EQ("1-3", lists[0].adds);
363 EXPECT_EQ("7", lists[0].subs);
364 if (lists.size() == 2) {
365 // Old style database won't have the second entry since it creates the lists
366 // when it receives an update containing that list. The filter-based
367 // database has these values hard coded.
368 EXPECT_EQ(safe_browsing_util::kPhishingList, lists[1].name);
369 EXPECT_TRUE(lists[1].adds.empty());
370 EXPECT_TRUE(lists[1].subs.empty());
373 // Add a phishing add chunk.
374 chunk.hosts.clear();
375 InsertAddChunkHostPrefixUrl(&chunk, 47, "www.evil.com/",
376 "www.evil.com/phishing.html");
377 chunks.clear();
378 chunks.push_back(chunk);
379 ASSERT_TRUE(database_->UpdateStarted(&lists));
380 database_->InsertChunks(safe_browsing_util::kPhishingList, chunks);
382 // Insert some phishing sub chunks.
383 chunk.hosts.clear();
384 InsertSubChunkHostPrefixUrl(&chunk, 200, 1999, "www.phishy.com/",
385 "www.phishy.com/notevil1.html");
386 chunks.clear();
387 chunks.push_back(chunk);
388 database_->InsertChunks(safe_browsing_util::kPhishingList, chunks);
390 chunk.hosts.clear();
391 InsertSubChunkHostPrefixUrl(&chunk, 201, 1999, "www.phishy2.com/",
392 "www.phishy2.com/notevil1.html");
393 chunks.clear();
394 chunks.push_back(chunk);
395 database_->InsertChunks(safe_browsing_util::kPhishingList, chunks);
396 database_->UpdateFinished(true);
398 GetListsInfo(&lists);
399 ASSERT_EQ(2U, lists.size());
400 EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
401 EXPECT_EQ("1-3", lists[0].adds);
402 EXPECT_EQ("7", lists[0].subs);
403 EXPECT_EQ(safe_browsing_util::kPhishingList, lists[1].name);
404 EXPECT_EQ("47", lists[1].adds);
405 EXPECT_EQ("200-201", lists[1].subs);
408 TEST_F(SafeBrowsingDatabaseTest, ListNameForBrowseAndDownload) {
409 database_.reset();
410 base::MessageLoop loop;
411 SafeBrowsingStoreFile* browse_store = new SafeBrowsingStoreFile();
412 SafeBrowsingStoreFile* download_store = new SafeBrowsingStoreFile();
413 SafeBrowsingStoreFile* csd_whitelist_store = new SafeBrowsingStoreFile();
414 SafeBrowsingStoreFile* download_whitelist_store = new SafeBrowsingStoreFile();
415 SafeBrowsingStoreFile* extension_blacklist_store =
416 new SafeBrowsingStoreFile();
417 SafeBrowsingStoreFile* ip_blacklist_store = new SafeBrowsingStoreFile();
418 database_.reset(new SafeBrowsingDatabaseNew(browse_store,
419 download_store,
420 csd_whitelist_store,
421 download_whitelist_store,
422 extension_blacklist_store,
423 NULL,
424 ip_blacklist_store));
425 database_->Init(database_filename_);
427 SBChunkList chunks;
428 SBChunk chunk;
430 // Insert malware, phish, binurl and bindownload add chunks.
431 InsertAddChunkHostPrefixUrl(&chunk, 1, "www.evil.com/",
432 "www.evil.com/malware.html");
433 chunks.push_back(chunk);
434 std::vector<SBListChunkRanges> lists;
435 ASSERT_TRUE(database_->UpdateStarted(&lists));
436 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
438 chunk.hosts.clear();
439 InsertAddChunkHostPrefixUrl(&chunk, 2, "www.foo.com/",
440 "www.foo.com/malware.html");
441 chunks.clear();
442 chunks.push_back(chunk);
443 database_->InsertChunks(safe_browsing_util::kPhishingList, chunks);
445 chunk.hosts.clear();
446 InsertAddChunkHostPrefixUrl(&chunk, 3, "www.whatever.com/",
447 "www.whatever.com/download.html");
448 chunks.clear();
449 chunks.push_back(chunk);
450 database_->InsertChunks(safe_browsing_util::kBinUrlList, chunks);
452 chunk.hosts.clear();
453 InsertAddChunkHostFullHashes(&chunk, 5, "www.forwhitelist.com/",
454 "www.forwhitelist.com/a.html");
455 chunks.clear();
456 chunks.push_back(chunk);
457 database_->InsertChunks(safe_browsing_util::kCsdWhiteList, chunks);
459 chunk.hosts.clear();
460 InsertAddChunkHostFullHashes(&chunk, 6, "www.download.com/",
461 "www.download.com/");
463 chunks.clear();
464 chunks.push_back(chunk);
465 database_->InsertChunks(safe_browsing_util::kDownloadWhiteList, chunks);
467 chunk.hosts.clear();
468 InsertAddChunkHostFullHashes(&chunk, 8,
469 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
470 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
472 chunks.clear();
473 chunks.push_back(chunk);
474 database_->InsertChunks(safe_browsing_util::kExtensionBlacklist, chunks);
476 chunk.hosts.clear();
477 InsertAddChunkFullHash(&chunk, 9, "::ffff:192.168.1.0", 120);
479 chunks.clear();
480 chunks.push_back(chunk);
481 database_->InsertChunks(safe_browsing_util::kIPBlacklist, chunks);
483 database_->UpdateFinished(true);
485 GetListsInfo(&lists);
486 ASSERT_EQ(7U, lists.size());
487 EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
488 EXPECT_EQ("1", lists[0].adds);
489 EXPECT_TRUE(lists[0].subs.empty());
490 EXPECT_EQ(safe_browsing_util::kPhishingList, lists[1].name);
491 EXPECT_EQ("2", lists[1].adds);
492 EXPECT_TRUE(lists[1].subs.empty());
493 EXPECT_EQ(safe_browsing_util::kBinUrlList, lists[2].name);
494 EXPECT_EQ("3", lists[2].adds);
495 EXPECT_TRUE(lists[2].subs.empty());
496 EXPECT_EQ(safe_browsing_util::kCsdWhiteList, lists[3].name);
497 EXPECT_EQ("5", lists[3].adds);
498 EXPECT_TRUE(lists[3].subs.empty());
499 EXPECT_EQ(safe_browsing_util::kDownloadWhiteList, lists[4].name);
500 EXPECT_EQ("6", lists[4].adds);
501 EXPECT_TRUE(lists[4].subs.empty());
502 EXPECT_EQ(safe_browsing_util::kExtensionBlacklist, lists[5].name);
503 EXPECT_EQ("8", lists[5].adds);
504 EXPECT_TRUE(lists[5].subs.empty());
505 EXPECT_EQ(safe_browsing_util::kIPBlacklist, lists[6].name);
506 EXPECT_EQ("9", lists[6].adds);
507 EXPECT_TRUE(lists[6].subs.empty());
509 database_.reset();
512 // Checks database reading and writing for browse.
513 TEST_F(SafeBrowsingDatabaseTest, BrowseDatabase) {
514 SBChunkList chunks;
515 SBChunk chunk;
517 // Add a simple chunk with one hostkey.
518 InsertAddChunkHost2PrefixUrls(&chunk, 1, "www.evil.com/",
519 "www.evil.com/phishing.html",
520 "www.evil.com/malware.html");
521 chunks.push_back(chunk);
522 std::vector<SBListChunkRanges> lists;
523 ASSERT_TRUE(database_->UpdateStarted(&lists));
524 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
526 chunk.hosts.clear();
527 InsertAddChunkHost2PrefixUrls(&chunk, 2, "www.evil.com/",
528 "www.evil.com/notevil1.html",
529 "www.evil.com/notevil2.html");
530 InsertAddChunkHost2PrefixUrls(&chunk, 2, "www.good.com/",
531 "www.good.com/good1.html",
532 "www.good.com/good2.html");
533 chunks.clear();
534 chunks.push_back(chunk);
535 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
537 // and a chunk with an IP-based host
538 chunk.hosts.clear();
539 InsertAddChunkHostPrefixUrl(&chunk, 3, "192.168.0.1/",
540 "192.168.0.1/malware.html");
541 chunks.clear();
542 chunks.push_back(chunk);
543 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
545 // A chunk with a full hash.
546 chunk.hosts.clear();
547 InsertAddChunkHostFullHashes(&chunk, 7, "www.evil.com/",
548 "www.evil.com/evil.html");
549 chunks.clear();
550 chunks.push_back(chunk);
551 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
553 database_->UpdateFinished(true);
555 // Make sure they were added correctly.
556 GetListsInfo(&lists);
557 ASSERT_LE(1U, lists.size());
558 EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
559 EXPECT_EQ("1-3,7", lists[0].adds);
560 EXPECT_TRUE(lists[0].subs.empty());
562 std::vector<SBPrefix> prefix_hits;
563 std::vector<SBFullHashResult> cache_hits;
564 EXPECT_TRUE(database_->ContainsBrowseUrl(
565 GURL("http://www.evil.com/phishing.html"), &prefix_hits, &cache_hits));
566 ASSERT_EQ(1U, prefix_hits.size());
567 EXPECT_EQ(SBPrefixForString("www.evil.com/phishing.html"), prefix_hits[0]);
568 EXPECT_TRUE(cache_hits.empty());
570 EXPECT_TRUE(database_->ContainsBrowseUrl(
571 GURL("http://www.evil.com/malware.html"), &prefix_hits, &cache_hits));
573 EXPECT_TRUE(database_->ContainsBrowseUrl(
574 GURL("http://www.evil.com/notevil1.html"), &prefix_hits, &cache_hits));
576 EXPECT_TRUE(database_->ContainsBrowseUrl(
577 GURL("http://www.evil.com/notevil2.html"), &prefix_hits, &cache_hits));
579 EXPECT_TRUE(database_->ContainsBrowseUrl(
580 GURL("http://www.good.com/good1.html"), &prefix_hits, &cache_hits));
582 EXPECT_TRUE(database_->ContainsBrowseUrl(
583 GURL("http://www.good.com/good2.html"), &prefix_hits, &cache_hits));
585 EXPECT_TRUE(database_->ContainsBrowseUrl(
586 GURL("http://192.168.0.1/malware.html"), &prefix_hits, &cache_hits));
588 EXPECT_FALSE(database_->ContainsBrowseUrl(
589 GURL("http://www.evil.com/"), &prefix_hits, &cache_hits));
590 EXPECT_TRUE(prefix_hits.empty());
591 EXPECT_TRUE(cache_hits.empty());
593 EXPECT_FALSE(database_->ContainsBrowseUrl(
594 GURL("http://www.evil.com/robots.txt"), &prefix_hits, &cache_hits));
596 EXPECT_TRUE(database_->ContainsBrowseUrl(
597 GURL("http://www.evil.com/evil.html"), &prefix_hits, &cache_hits));
598 ASSERT_EQ(1U, prefix_hits.size());
599 EXPECT_EQ(SBPrefixForString("www.evil.com/evil.html"), prefix_hits[0]);
601 // Attempt to re-add the first chunk (should be a no-op).
602 // see bug: http://code.google.com/p/chromium/issues/detail?id=4522
603 chunk.hosts.clear();
604 InsertAddChunkHost2PrefixUrls(&chunk, 1, "www.evil.com/",
605 "www.evil.com/phishing.html",
606 "www.evil.com/malware.html");
607 chunks.clear();
608 chunks.push_back(chunk);
609 ASSERT_TRUE(database_->UpdateStarted(&lists));
610 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
611 database_->UpdateFinished(true);
613 GetListsInfo(&lists);
614 ASSERT_LE(1U, lists.size());
615 EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
616 EXPECT_EQ("1-3,7", lists[0].adds);
617 EXPECT_TRUE(lists[0].subs.empty());
619 // Test removing a single prefix from the add chunk.
620 chunk.hosts.clear();
621 InsertSubChunkHostPrefixUrl(&chunk, 4, 2, "www.evil.com/",
622 "www.evil.com/notevil1.html");
623 chunks.clear();
624 chunks.push_back(chunk);
625 ASSERT_TRUE(database_->UpdateStarted(&lists));
626 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
628 database_->UpdateFinished(true);
630 EXPECT_TRUE(database_->ContainsBrowseUrl(
631 GURL("http://www.evil.com/phishing.html"), &prefix_hits, &cache_hits));
632 ASSERT_EQ(1U, prefix_hits.size());
633 EXPECT_EQ(SBPrefixForString("www.evil.com/phishing.html"), prefix_hits[0]);
634 EXPECT_TRUE(cache_hits.empty());
636 EXPECT_FALSE(database_->ContainsBrowseUrl(
637 GURL("http://www.evil.com/notevil1.html"), &prefix_hits, &cache_hits));
638 EXPECT_TRUE(prefix_hits.empty());
639 EXPECT_TRUE(cache_hits.empty());
641 EXPECT_TRUE(database_->ContainsBrowseUrl(
642 GURL("http://www.evil.com/notevil2.html"), &prefix_hits, &cache_hits));
644 EXPECT_TRUE(database_->ContainsBrowseUrl(
645 GURL("http://www.good.com/good1.html"), &prefix_hits, &cache_hits));
647 EXPECT_TRUE(database_->ContainsBrowseUrl(
648 GURL("http://www.good.com/good2.html"), &prefix_hits, &cache_hits));
650 GetListsInfo(&lists);
651 ASSERT_LE(1U, lists.size());
652 EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
653 EXPECT_EQ("1-3,7", lists[0].adds);
654 EXPECT_EQ("4", lists[0].subs);
656 // Test the same sub chunk again. This should be a no-op.
657 // see bug: http://code.google.com/p/chromium/issues/detail?id=4522
658 chunk.hosts.clear();
659 InsertSubChunkHostPrefixUrl(&chunk, 4, 2, "www.evil.com/",
660 "www.evil.com/notevil1.html");
661 chunks.clear();
662 chunks.push_back(chunk);
664 ASSERT_TRUE(database_->UpdateStarted(&lists));
665 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
666 database_->UpdateFinished(true);
668 GetListsInfo(&lists);
669 ASSERT_LE(1U, lists.size());
670 EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
671 EXPECT_EQ("1-3,7", lists[0].adds);
672 EXPECT_EQ("4", lists[0].subs);
674 // Test removing all the prefixes from an add chunk.
675 ASSERT_TRUE(database_->UpdateStarted(&lists));
676 AddDelChunk(safe_browsing_util::kMalwareList, 2);
677 database_->UpdateFinished(true);
679 EXPECT_FALSE(database_->ContainsBrowseUrl(
680 GURL("http://www.evil.com/notevil2.html"), &prefix_hits, &cache_hits));
682 EXPECT_FALSE(database_->ContainsBrowseUrl(
683 GURL("http://www.good.com/good1.html"), &prefix_hits, &cache_hits));
685 EXPECT_FALSE(database_->ContainsBrowseUrl(
686 GURL("http://www.good.com/good2.html"), &prefix_hits, &cache_hits));
688 GetListsInfo(&lists);
689 ASSERT_LE(1U, lists.size());
690 EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
691 EXPECT_EQ("1,3,7", lists[0].adds);
692 EXPECT_EQ("4", lists[0].subs);
694 // The adddel command exposed a bug in the transaction code where any
695 // transaction after it would fail. Add a dummy entry and remove it to
696 // make sure the transcation works fine.
697 chunk.hosts.clear();
698 InsertAddChunkHostPrefixUrl(&chunk, 44, "www.redherring.com/",
699 "www.redherring.com/index.html");
700 chunks.clear();
701 chunks.push_back(chunk);
702 ASSERT_TRUE(database_->UpdateStarted(&lists));
703 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
705 // Now remove the dummy entry. If there are any problems with the
706 // transactions, asserts will fire.
707 AddDelChunk(safe_browsing_util::kMalwareList, 44);
709 // Test the subdel command.
710 SubDelChunk(safe_browsing_util::kMalwareList, 4);
711 database_->UpdateFinished(true);
713 GetListsInfo(&lists);
714 ASSERT_LE(1U, lists.size());
715 EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
716 EXPECT_EQ("1,3,7", lists[0].adds);
717 EXPECT_TRUE(lists[0].subs.empty());
719 // Test a sub command coming in before the add.
720 chunk.hosts.clear();
721 InsertSubChunkHost2PrefixUrls(&chunk, 5, 10,
722 "www.notevilanymore.com/",
723 "www.notevilanymore.com/index.html",
724 "www.notevilanymore.com/good.html");
725 chunks.clear();
726 chunks.push_back(chunk);
727 ASSERT_TRUE(database_->UpdateStarted(&lists));
728 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
729 database_->UpdateFinished(true);
731 EXPECT_FALSE(database_->ContainsBrowseUrl(
732 GURL("http://www.notevilanymore.com/index.html"),
733 &prefix_hits,
734 &cache_hits));
736 // Now insert the tardy add chunk and we don't expect them to appear
737 // in database because of the previous sub chunk.
738 chunk.hosts.clear();
739 InsertAddChunkHost2PrefixUrls(&chunk, 10, "www.notevilanymore.com/",
740 "www.notevilanymore.com/index.html",
741 "www.notevilanymore.com/good.html");
742 chunks.clear();
743 chunks.push_back(chunk);
744 ASSERT_TRUE(database_->UpdateStarted(&lists));
745 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
746 database_->UpdateFinished(true);
748 EXPECT_FALSE(database_->ContainsBrowseUrl(
749 GURL("http://www.notevilanymore.com/index.html"),
750 &prefix_hits,
751 &cache_hits));
753 EXPECT_FALSE(database_->ContainsBrowseUrl(
754 GURL("http://www.notevilanymore.com/good.html"),
755 &prefix_hits,
756 &cache_hits));
758 // Reset and reload the database. The database will rely on the prefix set.
759 database_.reset(new SafeBrowsingDatabaseNew);
760 database_->Init(database_filename_);
762 // Check that a prefix still hits.
763 EXPECT_TRUE(database_->ContainsBrowseUrl(
764 GURL("http://www.evil.com/phishing.html"), &prefix_hits, &cache_hits));
765 ASSERT_EQ(1U, prefix_hits.size());
766 EXPECT_EQ(SBPrefixForString("www.evil.com/phishing.html"), prefix_hits[0]);
768 // Also check that it's not just always returning true in this case.
769 EXPECT_FALSE(database_->ContainsBrowseUrl(
770 GURL("http://www.evil.com/"), &prefix_hits, &cache_hits));
772 // Check that the full hash is still present.
773 EXPECT_TRUE(database_->ContainsBrowseUrl(
774 GURL("http://www.evil.com/evil.html"), &prefix_hits, &cache_hits));
775 ASSERT_EQ(1U, prefix_hits.size());
776 EXPECT_EQ(SBPrefixForString("www.evil.com/evil.html"), prefix_hits[0]);
780 // Test adding zero length chunks to the database.
781 TEST_F(SafeBrowsingDatabaseTest, ZeroSizeChunk) {
782 SBChunkList chunks;
783 SBChunk chunk;
785 // Populate with a couple of normal chunks.
786 InsertAddChunkHost2PrefixUrls(&chunk, 1, "www.test.com/",
787 "www.test.com/test1.html",
788 "www.test.com/test2.html");
789 chunks.clear();
790 chunks.push_back(chunk);
792 chunk.hosts.clear();
793 InsertAddChunkHost2PrefixUrls(&chunk, 10, "www.random.com/",
794 "www.random.com/random1.html",
795 "www.random.com/random2.html");
796 chunks.push_back(chunk);
798 std::vector<SBListChunkRanges> lists;
799 ASSERT_TRUE(database_->UpdateStarted(&lists));
800 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
801 database_->UpdateFinished(true);
803 // Add an empty ADD and SUB chunk.
804 GetListsInfo(&lists);
805 ASSERT_LE(1U, lists.size());
806 EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
807 EXPECT_EQ("1,10", lists[0].adds);
808 EXPECT_TRUE(lists[0].subs.empty());
810 SBChunk empty_chunk;
811 empty_chunk.chunk_number = 19;
812 empty_chunk.is_add = true;
813 chunks.clear();
814 chunks.push_back(empty_chunk);
815 ASSERT_TRUE(database_->UpdateStarted(&lists));
816 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
817 chunks.clear();
818 empty_chunk.chunk_number = 7;
819 empty_chunk.is_add = false;
820 chunks.push_back(empty_chunk);
821 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
822 database_->UpdateFinished(true);
824 GetListsInfo(&lists);
825 ASSERT_LE(1U, lists.size());
826 EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
827 EXPECT_EQ("1,10,19", lists[0].adds);
828 EXPECT_EQ("7", lists[0].subs);
830 // Add an empty chunk along with a couple that contain data. This should
831 // result in the chunk range being reduced in size.
832 empty_chunk.hosts.clear();
833 InsertAddChunkHostPrefixUrl(&empty_chunk, 20, "www.notempy.com/",
834 "www.notempty.com/full1.html");
835 chunks.clear();
836 chunks.push_back(empty_chunk);
838 empty_chunk.chunk_number = 21;
839 empty_chunk.is_add = true;
840 empty_chunk.hosts.clear();
841 chunks.push_back(empty_chunk);
843 empty_chunk.hosts.clear();
844 InsertAddChunkHostPrefixUrl(&empty_chunk, 22, "www.notempy.com/",
845 "www.notempty.com/full2.html");
846 chunks.push_back(empty_chunk);
848 ASSERT_TRUE(database_->UpdateStarted(&lists));
849 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
850 database_->UpdateFinished(true);
852 std::vector<SBPrefix> prefix_hits;
853 std::vector<SBFullHashResult> cache_hits;
854 EXPECT_TRUE(database_->ContainsBrowseUrl(
855 GURL("http://www.notempty.com/full1.html"), &prefix_hits, &cache_hits));
856 EXPECT_TRUE(database_->ContainsBrowseUrl(
857 GURL("http://www.notempty.com/full2.html"), &prefix_hits, &cache_hits));
859 GetListsInfo(&lists);
860 ASSERT_LE(1U, lists.size());
861 EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
862 EXPECT_EQ("1,10,19-22", lists[0].adds);
863 EXPECT_EQ("7", lists[0].subs);
865 // Handle AddDel and SubDel commands for empty chunks.
866 ASSERT_TRUE(database_->UpdateStarted(&lists));
867 AddDelChunk(safe_browsing_util::kMalwareList, 21);
868 database_->UpdateFinished(true);
870 GetListsInfo(&lists);
871 ASSERT_LE(1U, lists.size());
872 EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
873 EXPECT_EQ("1,10,19-20,22", lists[0].adds);
874 EXPECT_EQ("7", lists[0].subs);
876 ASSERT_TRUE(database_->UpdateStarted(&lists));
877 SubDelChunk(safe_browsing_util::kMalwareList, 7);
878 database_->UpdateFinished(true);
880 GetListsInfo(&lists);
881 ASSERT_LE(1U, lists.size());
882 EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
883 EXPECT_EQ("1,10,19-20,22", lists[0].adds);
884 EXPECT_TRUE(lists[0].subs.empty());
887 // Utility function for setting up the database for the caching test.
888 void SafeBrowsingDatabaseTest::PopulateDatabaseForCacheTest() {
889 SBChunkList chunks;
890 SBChunk chunk;
891 // Add a simple chunk with one hostkey and cache it.
892 InsertAddChunkHost2PrefixUrls(&chunk, 1, "www.evil.com/",
893 "www.evil.com/phishing.html",
894 "www.evil.com/malware.html");
895 chunks.push_back(chunk);
897 std::vector<SBListChunkRanges> lists;
898 ASSERT_TRUE(database_->UpdateStarted(&lists));
899 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
900 database_->UpdateFinished(true);
902 // Add the GetHash results to the cache.
903 SBFullHashResult full_hash;
904 full_hash.hash = SBFullHashForString("www.evil.com/phishing.html");
905 full_hash.list_id = safe_browsing_util::MALWARE;
907 std::vector<SBFullHashResult> results;
908 results.push_back(full_hash);
910 full_hash.hash = SBFullHashForString("www.evil.com/malware.html");
911 results.push_back(full_hash);
913 std::vector<SBPrefix> prefixes;
914 database_->CacheHashResults(prefixes, results, kCacheLifetime);
917 TEST_F(SafeBrowsingDatabaseTest, HashCaching) {
918 PopulateDatabaseForCacheTest();
920 // We should have both full hashes in the cache.
921 EXPECT_EQ(2U, database_->cached_browse_hashes_.size());
923 // Test the cache lookup for the first prefix.
924 std::vector<SBPrefix> prefix_hits;
925 std::vector<SBFullHashResult> cache_hits;
926 database_->ContainsBrowseUrl(
927 GURL("http://www.evil.com/phishing.html"), &prefix_hits, &cache_hits);
928 ASSERT_EQ(1U, cache_hits.size());
929 EXPECT_TRUE(SBFullHashEqual(
930 cache_hits[0].hash, SBFullHashForString("www.evil.com/phishing.html")));
932 prefix_hits.clear();
933 cache_hits.clear();
935 // Test the cache lookup for the second prefix.
936 database_->ContainsBrowseUrl(
937 GURL("http://www.evil.com/malware.html"), &prefix_hits, &cache_hits);
938 ASSERT_EQ(1U, cache_hits.size());
939 EXPECT_TRUE(SBFullHashEqual(
940 cache_hits[0].hash, SBFullHashForString("www.evil.com/malware.html")));
942 prefix_hits.clear();
943 cache_hits.clear();
945 // Test removing a prefix via a sub chunk.
946 SBChunk chunk;
947 SBChunkList chunks;
948 InsertSubChunkHostPrefixUrl(&chunk, 2, 1, "www.evil.com/",
949 "www.evil.com/phishing.html");
950 chunks.push_back(chunk);
952 std::vector<SBListChunkRanges> lists;
953 ASSERT_TRUE(database_->UpdateStarted(&lists));
954 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
955 database_->UpdateFinished(true);
957 // This prefix should still be there, but cached fullhash should be gone.
958 EXPECT_TRUE(database_->ContainsBrowseUrl(
959 GURL("http://www.evil.com/malware.html"), &prefix_hits, &cache_hits));
960 ASSERT_EQ(1U, prefix_hits.size());
961 EXPECT_EQ(SBPrefixForString("www.evil.com/malware.html"), prefix_hits[0]);
962 EXPECT_TRUE(cache_hits.empty());
963 prefix_hits.clear();
964 cache_hits.clear();
966 // This prefix should be gone.
967 database_->ContainsBrowseUrl(
968 GURL("http://www.evil.com/phishing.html"), &prefix_hits, &cache_hits);
969 EXPECT_TRUE(prefix_hits.empty());
970 EXPECT_TRUE(cache_hits.empty());
972 prefix_hits.clear();
973 cache_hits.clear();
975 // Test that an AddDel for the original chunk removes the last cached entry.
976 ASSERT_TRUE(database_->UpdateStarted(&lists));
977 AddDelChunk(safe_browsing_util::kMalwareList, 1);
978 database_->UpdateFinished(true);
979 database_->ContainsBrowseUrl(
980 GURL("http://www.evil.com/malware.html"), &prefix_hits, &cache_hits);
981 EXPECT_TRUE(cache_hits.empty());
982 EXPECT_TRUE(database_->cached_browse_hashes_.empty());
984 prefix_hits.clear();
985 cache_hits.clear();
987 // Test that the cache won't return expired values. First we have to adjust
988 // the cached entries' received time to make them older, since the database
989 // cache insert uses Time::Now(). First, store some entries.
990 PopulateDatabaseForCacheTest();
992 std::vector<SBFullHashCached>* hash_cache = &database_->cached_browse_hashes_;
993 EXPECT_EQ(2U, hash_cache->size());
995 // Now adjust one of the entries times to be expired.
996 const Time expired = Time::Now() - TimeDelta::FromMinutes(1);
997 const SBPrefix key = SBPrefixForString("www.evil.com/malware.html");
998 std::vector<SBFullHashCached>::iterator iter;
999 for (iter = hash_cache->begin(); iter != hash_cache->end(); ++iter) {
1000 if (iter->hash.prefix == key) {
1001 iter->expire_after = expired;
1002 break;
1005 EXPECT_TRUE(iter != hash_cache->end());
1007 database_->ContainsBrowseUrl(
1008 GURL("http://www.evil.com/malware.html"), &prefix_hits, &cache_hits);
1009 EXPECT_TRUE(cache_hits.empty());
1011 // This entry should still exist.
1012 database_->ContainsBrowseUrl(
1013 GURL("http://www.evil.com/phishing.html"), &prefix_hits, &cache_hits);
1014 EXPECT_EQ(1U, cache_hits.size());
1016 // Testing prefix miss caching. First, we clear out the existing database,
1017 // Since PopulateDatabaseForCacheTest() doesn't handle adding duplicate
1018 // chunks.
1019 ASSERT_TRUE(database_->UpdateStarted(&lists));
1020 AddDelChunk(safe_browsing_util::kMalwareList, 1);
1021 database_->UpdateFinished(true);
1023 std::vector<SBPrefix> prefix_misses;
1024 std::vector<SBFullHashResult> empty_full_hash;
1025 prefix_misses.push_back(SBPrefixForString("http://www.bad.com/malware.html"));
1026 prefix_misses.push_back(
1027 SBPrefixForString("http://www.bad.com/phishing.html"));
1028 database_->CacheHashResults(prefix_misses, empty_full_hash, kCacheLifetime);
1030 // Prefixes with no full results are misses.
1031 EXPECT_EQ(2U, database_->prefix_miss_cache_.size());
1033 // Update the database.
1034 PopulateDatabaseForCacheTest();
1036 // Prefix miss cache should be cleared.
1037 EXPECT_TRUE(database_->prefix_miss_cache_.empty());
1039 // Cache a GetHash miss for a particular prefix, and even though the prefix is
1040 // in the database, it is flagged as a miss so looking up the associated URL
1041 // will not succeed.
1042 prefix_hits.clear();
1043 cache_hits.clear();
1044 prefix_misses.clear();
1045 empty_full_hash.clear();
1046 prefix_misses.push_back(SBPrefixForString("www.evil.com/phishing.html"));
1047 database_->CacheHashResults(prefix_misses, empty_full_hash, kCacheLifetime);
1048 EXPECT_FALSE(database_->ContainsBrowseUrl(
1049 GURL("http://www.evil.com/phishing.html"), &prefix_hits, &cache_hits));
1051 prefix_hits.clear();
1052 cache_hits.clear();
1054 // Test receiving a full add chunk.
1055 chunk.hosts.clear();
1056 InsertAddChunkHost2FullHashes(&chunk, 20, "www.fullevil.com/",
1057 "www.fullevil.com/bad1.html",
1058 "www.fullevil.com/bad2.html");
1059 chunks.clear();
1060 chunks.push_back(chunk);
1061 ASSERT_TRUE(database_->UpdateStarted(&lists));
1062 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
1063 database_->UpdateFinished(true);
1065 EXPECT_TRUE(database_->ContainsBrowseUrl(
1066 GURL("http://www.fullevil.com/bad1.html"), &prefix_hits, &cache_hits));
1067 ASSERT_EQ(1U, prefix_hits.size());
1068 EXPECT_EQ(SBPrefixForString("www.fullevil.com/bad1.html"), prefix_hits[0]);
1069 EXPECT_TRUE(cache_hits.empty());
1070 prefix_hits.clear();
1071 cache_hits.clear();
1073 EXPECT_TRUE(database_->ContainsBrowseUrl(
1074 GURL("http://www.fullevil.com/bad2.html"), &prefix_hits, &cache_hits));
1075 ASSERT_EQ(1U, prefix_hits.size());
1076 EXPECT_EQ(SBPrefixForString("www.fullevil.com/bad2.html"), prefix_hits[0]);
1077 EXPECT_TRUE(cache_hits.empty());
1078 prefix_hits.clear();
1079 cache_hits.clear();
1081 // Test receiving a full sub chunk, which will remove one of the full adds.
1082 chunk.hosts.clear();
1083 InsertSubChunkHostFullHash(&chunk, 200, 20,
1084 "www.fullevil.com/",
1085 "www.fullevil.com/bad1.html");
1086 chunks.clear();
1087 chunks.push_back(chunk);
1088 ASSERT_TRUE(database_->UpdateStarted(&lists));
1089 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
1090 database_->UpdateFinished(true);
1092 EXPECT_FALSE(database_->ContainsBrowseUrl(
1093 GURL("http://www.fullevil.com/bad1.html"), &prefix_hits, &cache_hits));
1094 EXPECT_TRUE(prefix_hits.empty());
1095 EXPECT_TRUE(cache_hits.empty());
1097 // There should be one remaining full add.
1098 EXPECT_TRUE(database_->ContainsBrowseUrl(
1099 GURL("http://www.fullevil.com/bad2.html"), &prefix_hits, &cache_hits));
1100 ASSERT_EQ(1U, prefix_hits.size());
1101 EXPECT_EQ(SBPrefixForString("www.fullevil.com/bad2.html"), prefix_hits[0]);
1102 EXPECT_TRUE(cache_hits.empty());
1103 prefix_hits.clear();
1104 cache_hits.clear();
1106 // Now test an AddDel for the remaining full add.
1107 ASSERT_TRUE(database_->UpdateStarted(&lists));
1108 AddDelChunk(safe_browsing_util::kMalwareList, 20);
1109 database_->UpdateFinished(true);
1111 EXPECT_FALSE(database_->ContainsBrowseUrl(
1112 GURL("http://www.fullevil.com/bad1.html"), &prefix_hits, &cache_hits));
1113 EXPECT_FALSE(database_->ContainsBrowseUrl(
1114 GURL("http://www.fullevil.com/bad2.html"), &prefix_hits, &cache_hits));
1116 // Add a fullhash which has a prefix collision for a known url.
1117 static const char kExampleFine[] = "www.example.com/fine.html";
1118 static const char kExampleCollision[] =
1119 "www.example.com/3123364814/malware.htm";
1120 ASSERT_EQ(SBPrefixForString(kExampleFine),
1121 SBPrefixForString(kExampleCollision));
1122 ASSERT_TRUE(database_->UpdateStarted(&lists));
1124 SBChunkList chunks;
1125 SBChunk chunk;
1126 InsertAddChunkHostPrefixUrl(&chunk, 21, "www.example.com/",
1127 kExampleCollision);
1128 chunks.push_back(chunk);
1129 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
1131 database_->UpdateFinished(true);
1133 // Cache gethash response for |kExampleCollision|.
1135 SBFullHashResult result;
1136 result.hash = SBFullHashForString(kExampleCollision);
1137 result.list_id = safe_browsing_util::MALWARE;
1138 database_->CacheHashResults(std::vector<SBPrefix>(1, result.hash.prefix),
1139 std::vector<SBFullHashResult>(1, result),
1140 kCacheLifetime);
1143 // Expect a prefix hit due to the collision between |kExampleFine| and
1144 // |kExampleCollision|, with the gethash showing only |kExampleCollision|.
1145 EXPECT_TRUE(database_->ContainsBrowseUrl(
1146 GURL(std::string("http://") + kExampleFine), &prefix_hits, &cache_hits));
1147 ASSERT_EQ(1U, prefix_hits.size());
1148 EXPECT_EQ(SBPrefixForString(kExampleFine), prefix_hits[0]);
1149 ASSERT_EQ(1U, cache_hits.size());
1150 EXPECT_TRUE(SBFullHashEqual(cache_hits[0].hash,
1151 SBFullHashForString(kExampleCollision)));
1154 // Test that corrupt databases are appropriately handled, even if the
1155 // corruption is detected in the midst of the update.
1156 // TODO(shess): Disabled until ScopedLogMessageIgnorer resolved.
1157 // http://crbug.com/56448
1158 TEST_F(SafeBrowsingDatabaseTest, DISABLED_FileCorruptionHandling) {
1159 // Re-create the database in a captive message loop so that we can
1160 // influence task-posting. Database specifically needs to the
1161 // file-backed.
1162 database_.reset();
1163 base::MessageLoop loop;
1164 SafeBrowsingStoreFile* store = new SafeBrowsingStoreFile();
1165 database_.reset(new SafeBrowsingDatabaseNew(store, NULL, NULL, NULL, NULL,
1166 NULL, NULL));
1167 database_->Init(database_filename_);
1169 // This will cause an empty database to be created.
1170 std::vector<SBListChunkRanges> lists;
1171 ASSERT_TRUE(database_->UpdateStarted(&lists));
1172 database_->UpdateFinished(true);
1174 // Create a sub chunk to insert.
1175 SBChunkList chunks;
1176 SBChunk chunk;
1177 SBChunkHost host;
1178 host.host = SBPrefixForString("www.subbed.com/");
1179 host.entry = SBEntry::Create(SBEntry::SUB_PREFIX, 1);
1180 host.entry->set_chunk_id(7);
1181 host.entry->SetChunkIdAtPrefix(0, 19);
1182 host.entry->SetPrefixAt(0, SBPrefixForString("www.subbed.com/notevil1.html"));
1183 chunk.chunk_number = 7;
1184 chunk.is_add = false;
1185 chunk.hosts.clear();
1186 chunk.hosts.push_back(host);
1187 chunks.clear();
1188 chunks.push_back(chunk);
1190 // Corrupt the file by corrupting the checksum, which is not checked
1191 // until the entire table is read in |UpdateFinished()|.
1192 FILE* fp = base::OpenFile(database_filename_, "r+");
1193 ASSERT_TRUE(fp);
1194 ASSERT_NE(-1, fseek(fp, -8, SEEK_END));
1195 for (size_t i = 0; i < 8; ++i) {
1196 fputc('!', fp);
1198 fclose(fp);
1201 // The following code will cause DCHECKs, so suppress the crashes.
1202 ScopedLogMessageIgnorer ignorer;
1204 // Start an update. The insert will fail due to corruption.
1205 ASSERT_TRUE(database_->UpdateStarted(&lists));
1206 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
1207 database_->UpdateFinished(true);
1209 // Database file still exists until the corruption handler has run.
1210 EXPECT_TRUE(base::PathExists(database_filename_));
1212 // Flush through the corruption-handler task.
1213 VLOG(1) << "Expect failed check on: SafeBrowsing database reset";
1214 base::MessageLoop::current()->RunUntilIdle();
1217 // Database file should not exist.
1218 EXPECT_FALSE(base::PathExists(database_filename_));
1220 // Run the update again successfully.
1221 ASSERT_TRUE(database_->UpdateStarted(&lists));
1222 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
1223 database_->UpdateFinished(true);
1224 EXPECT_TRUE(base::PathExists(database_filename_));
1226 database_.reset();
1229 // Checks database reading and writing.
1230 TEST_F(SafeBrowsingDatabaseTest, ContainsDownloadUrl) {
1231 database_.reset();
1232 base::MessageLoop loop;
1233 SafeBrowsingStoreFile* browse_store = new SafeBrowsingStoreFile();
1234 SafeBrowsingStoreFile* download_store = new SafeBrowsingStoreFile();
1235 SafeBrowsingStoreFile* csd_whitelist_store = new SafeBrowsingStoreFile();
1236 database_.reset(new SafeBrowsingDatabaseNew(browse_store,
1237 download_store,
1238 csd_whitelist_store,
1239 NULL,
1240 NULL,
1241 NULL,
1242 NULL));
1243 database_->Init(database_filename_);
1245 const char kEvil1Host[] = "www.evil1.com/";
1246 const char kEvil1Url1[] = "www.evil1.com/download1/";
1247 const char kEvil1Url2[] = "www.evil1.com/download2.html";
1249 SBChunkList chunks;
1250 SBChunk chunk;
1251 // Add a simple chunk with one hostkey for download url list.
1252 InsertAddChunkHost2PrefixUrls(&chunk, 1, kEvil1Host,
1253 kEvil1Url1, kEvil1Url2);
1254 chunks.push_back(chunk);
1255 std::vector<SBListChunkRanges> lists;
1256 ASSERT_TRUE(database_->UpdateStarted(&lists));
1257 database_->InsertChunks(safe_browsing_util::kBinUrlList, chunks);
1258 database_->UpdateFinished(true);
1260 std::vector<SBPrefix> prefix_hits;
1261 std::vector<GURL> urls(1);
1263 urls[0] = GURL(std::string("http://") + kEvil1Url1);
1264 EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits));
1265 ASSERT_EQ(1U, prefix_hits.size());
1266 EXPECT_EQ(SBPrefixForString(kEvil1Url1), prefix_hits[0]);
1268 urls[0] = GURL(std::string("http://") + kEvil1Url2);
1269 EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits));
1270 ASSERT_EQ(1U, prefix_hits.size());
1271 EXPECT_EQ(SBPrefixForString(kEvil1Url2), prefix_hits[0]);
1273 urls[0] = GURL(std::string("https://") + kEvil1Url2);
1274 EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits));
1275 ASSERT_EQ(1U, prefix_hits.size());
1276 EXPECT_EQ(SBPrefixForString(kEvil1Url2), prefix_hits[0]);
1278 urls[0] = GURL(std::string("ftp://") + kEvil1Url2);
1279 EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits));
1280 ASSERT_EQ(1U, prefix_hits.size());
1281 EXPECT_EQ(SBPrefixForString(kEvil1Url2), prefix_hits[0]);
1283 urls[0] = GURL("http://www.randomevil.com");
1284 EXPECT_FALSE(database_->ContainsDownloadUrl(urls, &prefix_hits));
1286 // Should match with query args stripped.
1287 urls[0] = GURL(std::string("http://") + kEvil1Url2 + "?blah");
1288 EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits));
1289 ASSERT_EQ(1U, prefix_hits.size());
1290 EXPECT_EQ(SBPrefixForString(kEvil1Url2), prefix_hits[0]);
1292 // Should match with extra path stuff and query args stripped.
1293 urls[0] = GURL(std::string("http://") + kEvil1Url1 + "foo/bar?blah");
1294 EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits));
1295 ASSERT_EQ(1U, prefix_hits.size());
1296 EXPECT_EQ(SBPrefixForString(kEvil1Url1), prefix_hits[0]);
1298 // First hit in redirect chain is malware.
1299 urls.clear();
1300 urls.push_back(GURL(std::string("http://") + kEvil1Url1));
1301 urls.push_back(GURL("http://www.randomevil.com"));
1302 EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits));
1303 ASSERT_EQ(1U, prefix_hits.size());
1304 EXPECT_EQ(SBPrefixForString(kEvil1Url1), prefix_hits[0]);
1306 // Middle hit in redirect chain is malware.
1307 urls.clear();
1308 urls.push_back(GURL("http://www.randomevil.com"));
1309 urls.push_back(GURL(std::string("http://") + kEvil1Url1));
1310 urls.push_back(GURL("http://www.randomevil2.com"));
1311 EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits));
1312 ASSERT_EQ(1U, prefix_hits.size());
1313 EXPECT_EQ(SBPrefixForString(kEvil1Url1), prefix_hits[0]);
1315 // Final hit in redirect chain is malware.
1316 urls.clear();
1317 urls.push_back(GURL("http://www.randomevil.com"));
1318 urls.push_back(GURL(std::string("http://") + kEvil1Url1));
1319 EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits));
1320 ASSERT_EQ(1U, prefix_hits.size());
1321 EXPECT_EQ(SBPrefixForString(kEvil1Url1), prefix_hits[0]);
1323 // Multiple hits in redirect chain are in malware list.
1324 urls.clear();
1325 urls.push_back(GURL(std::string("http://") + kEvil1Url1));
1326 urls.push_back(GURL(std::string("https://") + kEvil1Url2));
1327 EXPECT_TRUE(database_->ContainsDownloadUrl(urls, &prefix_hits));
1328 ASSERT_EQ(2U, prefix_hits.size());
1329 EXPECT_EQ(SBPrefixForString(kEvil1Url1), prefix_hits[0]);
1330 EXPECT_EQ(SBPrefixForString(kEvil1Url2), prefix_hits[1]);
1331 database_.reset();
1334 // Checks that the whitelists are handled properly.
1335 TEST_F(SafeBrowsingDatabaseTest, Whitelists) {
1336 database_.reset();
1337 // We expect all calls to ContainsCsdWhitelistedUrl in particular to be made
1338 // from the IO thread. In general the whitelist lookups are thread-safe.
1339 content::TestBrowserThreadBundle thread_bundle_;
1341 // If the whitelist is disabled everything should match the whitelist.
1342 database_.reset(new SafeBrowsingDatabaseNew(new SafeBrowsingStoreFile(),
1343 NULL, NULL, NULL, NULL, NULL,
1344 NULL));
1345 database_->Init(database_filename_);
1346 EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl(
1347 GURL(std::string("http://www.phishing.com/"))));
1348 EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl(
1349 GURL(std::string("http://www.phishing.com/"))));
1350 EXPECT_TRUE(database_->ContainsDownloadWhitelistedString("asdf"));
1352 SafeBrowsingStoreFile* browse_store = new SafeBrowsingStoreFile();
1353 SafeBrowsingStoreFile* csd_whitelist_store = new SafeBrowsingStoreFile();
1354 SafeBrowsingStoreFile* download_whitelist_store = new SafeBrowsingStoreFile();
1355 SafeBrowsingStoreFile* extension_blacklist_store =
1356 new SafeBrowsingStoreFile();
1357 database_.reset(new SafeBrowsingDatabaseNew(browse_store, NULL,
1358 csd_whitelist_store,
1359 download_whitelist_store,
1360 extension_blacklist_store,
1361 NULL, NULL));
1362 database_->Init(database_filename_);
1364 const char kGood1Host[] = "www.good1.com/";
1365 const char kGood1Url1[] = "www.good1.com/a/b.html";
1366 const char kGood1Url2[] = "www.good1.com/b/";
1368 const char kGood2Host[] = "www.good2.com/";
1369 const char kGood2Url1[] = "www.good2.com/c"; // Should match '/c/bla'.
1371 // good3.com/a/b/c/d/e/f/g/ should match because it's a whitelist.
1372 const char kGood3Host[] = "good3.com/";
1373 const char kGood3Url1[] = "good3.com/";
1375 const char kGoodString[] = "good_string";
1377 SBChunkList download_chunks, csd_chunks;
1378 SBChunk chunk;
1379 // Add two simple chunks to the csd whitelist.
1380 InsertAddChunkHost2FullHashes(&chunk, 1, kGood1Host,
1381 kGood1Url1, kGood1Url2);
1382 csd_chunks.push_back(chunk);
1384 chunk.hosts.clear();
1385 InsertAddChunkHostFullHashes(&chunk, 2, kGood2Host, kGood2Url1);
1386 csd_chunks.push_back(chunk);
1388 chunk.hosts.clear();
1389 InsertAddChunkHostFullHashes(&chunk, 2, kGood2Host, kGood2Url1);
1390 download_chunks.push_back(chunk);
1392 chunk.hosts.clear();
1393 InsertAddChunkHostFullHashes(&chunk, 3, kGoodString, kGoodString);
1394 download_chunks.push_back(chunk);
1396 chunk.hosts.clear();
1397 InsertAddChunkHostFullHashes(&chunk, 4, kGood3Host, kGood3Url1);
1398 download_chunks.push_back(chunk);
1400 std::vector<SBListChunkRanges> lists;
1401 ASSERT_TRUE(database_->UpdateStarted(&lists));
1402 database_->InsertChunks(safe_browsing_util::kCsdWhiteList,
1403 csd_chunks);
1404 database_->InsertChunks(safe_browsing_util::kDownloadWhiteList,
1405 download_chunks);
1406 database_->UpdateFinished(true);
1408 EXPECT_FALSE(database_->ContainsCsdWhitelistedUrl(
1409 GURL(std::string("http://") + kGood1Host)));
1411 EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
1412 GURL(std::string("http://") + kGood1Url1)));
1413 EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
1414 GURL(std::string("http://") + kGood1Url1 + "?a=b")));
1416 EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
1417 GURL(std::string("http://") + kGood1Url2)));
1418 EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
1419 GURL(std::string("http://") + kGood1Url2 + "/c.html")));
1421 EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
1422 GURL(std::string("https://") + kGood1Url2 + "/c.html")));
1424 EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
1425 GURL(std::string("http://") + kGood2Url1 + "/c")));
1426 EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
1427 GURL(std::string("http://") + kGood2Url1 + "/c?bla")));
1428 EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
1429 GURL(std::string("http://") + kGood2Url1 + "/c/bla")));
1431 EXPECT_FALSE(database_->ContainsCsdWhitelistedUrl(
1432 GURL(std::string("http://www.google.com/"))));
1434 EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl(
1435 GURL(std::string("http://") + kGood2Url1 + "/c")));
1436 EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl(
1437 GURL(std::string("http://") + kGood2Url1 + "/c?bla")));
1438 EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl(
1439 GURL(std::string("http://") + kGood2Url1 + "/c/bla")));
1441 EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl(
1442 GURL(std::string("http://good3.com/a/b/c/d/e/f/g/"))));
1443 EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl(
1444 GURL(std::string("http://a.b.good3.com/"))));
1446 EXPECT_FALSE(database_->ContainsDownloadWhitelistedString("asdf"));
1447 EXPECT_TRUE(database_->ContainsDownloadWhitelistedString(kGoodString));
1449 EXPECT_FALSE(database_->ContainsDownloadWhitelistedUrl(
1450 GURL(std::string("http://www.google.com/"))));
1452 // The CSD whitelist killswitch is not present.
1453 EXPECT_FALSE(database_->IsCsdWhitelistKillSwitchOn());
1455 // Test only add the malware IP killswitch
1456 csd_chunks.clear();
1457 chunk.hosts.clear();
1458 InsertAddChunkHostFullHashes(
1459 &chunk, 15, "sb-ssl.google.com/",
1460 "sb-ssl.google.com/safebrowsing/csd/killswitch_malware");
1461 csd_chunks.push_back(chunk);
1462 ASSERT_TRUE(database_->UpdateStarted(&lists));
1463 database_->InsertChunks(safe_browsing_util::kCsdWhiteList, csd_chunks);
1464 database_->UpdateFinished(true);
1466 EXPECT_TRUE(database_->IsMalwareIPMatchKillSwitchOn());
1467 // The CSD whitelist killswitch is not present.
1468 EXPECT_FALSE(database_->IsCsdWhitelistKillSwitchOn());
1470 // Test that the kill-switch works as intended.
1471 csd_chunks.clear();
1472 download_chunks.clear();
1473 lists.clear();
1474 chunk.hosts.clear();
1475 InsertAddChunkHostFullHashes(&chunk, 5, "sb-ssl.google.com/",
1476 "sb-ssl.google.com/safebrowsing/csd/killswitch");
1477 csd_chunks.push_back(chunk);
1478 chunk.hosts.clear();
1479 InsertAddChunkHostFullHashes(&chunk, 5, "sb-ssl.google.com/",
1480 "sb-ssl.google.com/safebrowsing/csd/killswitch");
1481 download_chunks.push_back(chunk);
1483 ASSERT_TRUE(database_->UpdateStarted(&lists));
1484 database_->InsertChunks(safe_browsing_util::kCsdWhiteList, csd_chunks);
1485 database_->InsertChunks(safe_browsing_util::kDownloadWhiteList,
1486 download_chunks);
1487 database_->UpdateFinished(true);
1489 // The CSD whitelist killswitch is present.
1490 EXPECT_TRUE(database_->IsCsdWhitelistKillSwitchOn());
1491 EXPECT_TRUE(database_->IsMalwareIPMatchKillSwitchOn());
1492 EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
1493 GURL(std::string("https://") + kGood1Url2 + "/c.html")));
1494 EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
1495 GURL(std::string("http://www.google.com/"))));
1496 EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
1497 GURL(std::string("http://www.phishing_url.com/"))));
1499 EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl(
1500 GURL(std::string("https://") + kGood1Url2 + "/c.html")));
1501 EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl(
1502 GURL(std::string("http://www.google.com/"))));
1503 EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl(
1504 GURL(std::string("http://www.phishing_url.com/"))));
1506 EXPECT_TRUE(database_->ContainsDownloadWhitelistedString("asdf"));
1507 EXPECT_TRUE(database_->ContainsDownloadWhitelistedString(kGoodString));
1509 // Remove the kill-switch and verify that we can recover.
1510 csd_chunks.clear();
1511 download_chunks.clear();
1512 lists.clear();
1513 SBChunk sub_chunk;
1514 InsertSubChunkHostFullHash(&sub_chunk, 1, 5,
1515 "sb-ssl.google.com/",
1516 "sb-ssl.google.com/safebrowsing/csd/killswitch");
1517 csd_chunks.push_back(sub_chunk);
1519 sub_chunk.hosts.clear();
1520 InsertSubChunkHostFullHash(
1521 &sub_chunk, 10, 15, "sb-ssl.google.com/",
1522 "sb-ssl.google.com/safebrowsing/csd/killswitch_malware");
1523 csd_chunks.push_back(sub_chunk);
1525 sub_chunk.hosts.clear();
1526 InsertSubChunkHostFullHash(&sub_chunk, 1, 5,
1527 "sb-ssl.google.com/",
1528 "sb-ssl.google.com/safebrowsing/csd/killswitch");
1529 download_chunks.push_back(sub_chunk);
1531 ASSERT_TRUE(database_->UpdateStarted(&lists));
1532 database_->InsertChunks(safe_browsing_util::kCsdWhiteList, csd_chunks);
1533 database_->InsertChunks(safe_browsing_util::kDownloadWhiteList,
1534 download_chunks);
1535 database_->UpdateFinished(true);
1537 EXPECT_FALSE(database_->IsMalwareIPMatchKillSwitchOn());
1538 EXPECT_FALSE(database_->IsCsdWhitelistKillSwitchOn());
1539 EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
1540 GURL(std::string("https://") + kGood1Url2 + "/c.html")));
1541 EXPECT_TRUE(database_->ContainsCsdWhitelistedUrl(
1542 GURL(std::string("https://") + kGood2Url1 + "/c/bla")));
1543 EXPECT_FALSE(database_->ContainsCsdWhitelistedUrl(
1544 GURL(std::string("http://www.google.com/"))));
1545 EXPECT_FALSE(database_->ContainsCsdWhitelistedUrl(
1546 GURL(std::string("http://www.phishing_url.com/"))));
1548 EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl(
1549 GURL(std::string("https://") + kGood2Url1 + "/c/bla")));
1550 EXPECT_TRUE(database_->ContainsDownloadWhitelistedUrl(
1551 GURL(std::string("https://good3.com/"))));
1552 EXPECT_TRUE(database_->ContainsDownloadWhitelistedString(kGoodString));
1553 EXPECT_FALSE(database_->ContainsDownloadWhitelistedUrl(
1554 GURL(std::string("http://www.google.com/"))));
1555 EXPECT_FALSE(database_->ContainsDownloadWhitelistedUrl(
1556 GURL(std::string("http://www.phishing_url.com/"))));
1557 EXPECT_FALSE(database_->ContainsDownloadWhitelistedString("asdf"));
1559 database_.reset();
1562 // Test to make sure we could insert chunk list that
1563 // contains entries for the same host.
1564 TEST_F(SafeBrowsingDatabaseTest, SameHostEntriesOkay) {
1565 SBChunk chunk;
1567 // Add a malware add chunk with two entries of the same host.
1568 InsertAddChunkHostPrefixUrl(&chunk, 1, "www.evil.com/",
1569 "www.evil.com/malware1.html");
1570 InsertAddChunkHostPrefixUrl(&chunk, 1, "www.evil.com/",
1571 "www.evil.com/malware2.html");
1572 SBChunkList chunks;
1573 chunks.push_back(chunk);
1575 // Insert the testing chunks into database.
1576 std::vector<SBListChunkRanges> lists;
1577 ASSERT_TRUE(database_->UpdateStarted(&lists));
1578 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
1579 database_->UpdateFinished(true);
1581 GetListsInfo(&lists);
1582 ASSERT_LE(1U, lists.size());
1583 EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
1584 EXPECT_EQ("1", lists[0].adds);
1585 EXPECT_TRUE(lists[0].subs.empty());
1587 // Add a phishing add chunk with two entries of the same host.
1588 chunk.hosts.clear();
1589 InsertAddChunkHostPrefixUrl(&chunk, 47, "www.evil.com/",
1590 "www.evil.com/phishing1.html");
1591 InsertAddChunkHostPrefixUrl(&chunk, 47, "www.evil.com/",
1592 "www.evil.com/phishing2.html");
1593 chunks.clear();
1594 chunks.push_back(chunk);
1596 ASSERT_TRUE(database_->UpdateStarted(&lists));
1597 database_->InsertChunks(safe_browsing_util::kPhishingList, chunks);
1598 database_->UpdateFinished(true);
1600 GetListsInfo(&lists);
1601 ASSERT_EQ(2U, lists.size());
1602 EXPECT_EQ(safe_browsing_util::kMalwareList, lists[0].name);
1603 EXPECT_EQ("1", lists[0].adds);
1604 EXPECT_TRUE(lists[0].subs.empty());
1605 EXPECT_EQ(safe_browsing_util::kPhishingList, lists[1].name);
1606 EXPECT_EQ("47", lists[1].adds);
1607 EXPECT_TRUE(lists[1].subs.empty());
1609 std::vector<SBPrefix> prefix_hits;
1610 std::vector<SBFullHashResult> cache_hits;
1612 EXPECT_TRUE(database_->ContainsBrowseUrl(
1613 GURL("http://www.evil.com/malware1.html"), &prefix_hits, &cache_hits));
1614 EXPECT_TRUE(database_->ContainsBrowseUrl(
1615 GURL("http://www.evil.com/malware2.html"), &prefix_hits, &cache_hits));
1616 EXPECT_TRUE(database_->ContainsBrowseUrl(
1617 GURL("http://www.evil.com/phishing1.html"), &prefix_hits, &cache_hits));
1618 EXPECT_TRUE(database_->ContainsBrowseUrl(
1619 GURL("http://www.evil.com/phishing2.html"), &prefix_hits, &cache_hits));
1621 // Test removing a single prefix from the add chunk.
1622 // Remove the prefix that added first.
1623 chunk.hosts.clear();
1624 InsertSubChunkHostPrefixUrl(&chunk, 4, 1, "www.evil.com/",
1625 "www.evil.com/malware1.html");
1626 chunks.clear();
1627 chunks.push_back(chunk);
1628 ASSERT_TRUE(database_->UpdateStarted(&lists));
1629 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
1630 database_->UpdateFinished(true);
1632 // Remove the prefix that added last.
1633 chunk.hosts.clear();
1634 InsertSubChunkHostPrefixUrl(&chunk, 5, 47, "www.evil.com/",
1635 "www.evil.com/phishing2.html");
1636 chunks.clear();
1637 chunks.push_back(chunk);
1638 ASSERT_TRUE(database_->UpdateStarted(&lists));
1639 database_->InsertChunks(safe_browsing_util::kPhishingList, chunks);
1640 database_->UpdateFinished(true);
1642 // Verify that the database contains urls expected.
1643 EXPECT_FALSE(database_->ContainsBrowseUrl(
1644 GURL("http://www.evil.com/malware1.html"), &prefix_hits, &cache_hits));
1645 EXPECT_TRUE(database_->ContainsBrowseUrl(
1646 GURL("http://www.evil.com/malware2.html"), &prefix_hits, &cache_hits));
1647 EXPECT_TRUE(database_->ContainsBrowseUrl(
1648 GURL("http://www.evil.com/phishing1.html"), &prefix_hits, &cache_hits));
1649 EXPECT_FALSE(database_->ContainsBrowseUrl(
1650 GURL("http://www.evil.com/phishing2.html"), &prefix_hits, &cache_hits));
1653 // Test that an empty update doesn't actually update the database.
1654 // This isn't a functionality requirement, but it is a useful
1655 // optimization.
1656 TEST_F(SafeBrowsingDatabaseTest, EmptyUpdate) {
1657 SBChunkList chunks;
1658 SBChunk chunk;
1660 base::FilePath filename = database_->BrowseDBFilename(database_filename_);
1662 // Prime the database.
1663 std::vector<SBListChunkRanges> lists;
1664 ASSERT_TRUE(database_->UpdateStarted(&lists));
1666 InsertAddChunkHostPrefixUrl(&chunk, 1, "www.evil.com/",
1667 "www.evil.com/malware.html");
1668 chunks.clear();
1669 chunks.push_back(chunk);
1670 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
1671 database_->UpdateFinished(true);
1673 // Get an older time to reset the lastmod time for detecting whether
1674 // the file has been updated.
1675 base::File::Info before_info, after_info;
1676 ASSERT_TRUE(base::GetFileInfo(filename, &before_info));
1677 const Time old_last_modified =
1678 before_info.last_modified - TimeDelta::FromSeconds(10);
1680 // Inserting another chunk updates the database file. The sleep is
1681 // needed because otherwise the entire test can finish w/in the
1682 // resolution of the lastmod time.
1683 ASSERT_TRUE(base::TouchFile(filename, old_last_modified, old_last_modified));
1684 ASSERT_TRUE(base::GetFileInfo(filename, &before_info));
1685 ASSERT_TRUE(database_->UpdateStarted(&lists));
1686 chunk.hosts.clear();
1687 InsertAddChunkHostPrefixUrl(&chunk, 2, "www.foo.com/",
1688 "www.foo.com/malware.html");
1689 chunks.clear();
1690 chunks.push_back(chunk);
1691 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
1692 database_->UpdateFinished(true);
1693 ASSERT_TRUE(base::GetFileInfo(filename, &after_info));
1694 EXPECT_LT(before_info.last_modified, after_info.last_modified);
1696 // Deleting a chunk updates the database file.
1697 ASSERT_TRUE(base::TouchFile(filename, old_last_modified, old_last_modified));
1698 ASSERT_TRUE(base::GetFileInfo(filename, &before_info));
1699 ASSERT_TRUE(database_->UpdateStarted(&lists));
1700 AddDelChunk(safe_browsing_util::kMalwareList, chunk.chunk_number);
1701 database_->UpdateFinished(true);
1702 ASSERT_TRUE(base::GetFileInfo(filename, &after_info));
1703 EXPECT_LT(before_info.last_modified, after_info.last_modified);
1705 // Simply calling |UpdateStarted()| then |UpdateFinished()| does not
1706 // update the database file.
1707 ASSERT_TRUE(base::TouchFile(filename, old_last_modified, old_last_modified));
1708 ASSERT_TRUE(base::GetFileInfo(filename, &before_info));
1709 ASSERT_TRUE(database_->UpdateStarted(&lists));
1710 database_->UpdateFinished(true);
1711 ASSERT_TRUE(base::GetFileInfo(filename, &after_info));
1712 EXPECT_EQ(before_info.last_modified, after_info.last_modified);
1715 // Test that a filter file is written out during update and read back
1716 // in during setup.
1717 TEST_F(SafeBrowsingDatabaseTest, FilterFile) {
1718 // Create a database with trivial example data and write it out.
1720 SBChunkList chunks;
1721 SBChunk chunk;
1723 // Prime the database.
1724 std::vector<SBListChunkRanges> lists;
1725 ASSERT_TRUE(database_->UpdateStarted(&lists));
1727 InsertAddChunkHostPrefixUrl(&chunk, 1, "www.evil.com/",
1728 "www.evil.com/malware.html");
1729 chunks.clear();
1730 chunks.push_back(chunk);
1731 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
1732 database_->UpdateFinished(true);
1735 // Find the malware url in the database, don't find a good url.
1736 std::vector<SBPrefix> prefix_hits;
1737 std::vector<SBFullHashResult> cache_hits;
1738 EXPECT_TRUE(database_->ContainsBrowseUrl(
1739 GURL("http://www.evil.com/malware.html"), &prefix_hits, &cache_hits));
1740 EXPECT_FALSE(database_->ContainsBrowseUrl(
1741 GURL("http://www.good.com/goodware.html"), &prefix_hits, &cache_hits));
1743 base::FilePath filter_file = database_->PrefixSetForFilename(
1744 database_->BrowseDBFilename(database_filename_));
1746 // After re-creating the database, it should have a filter read from
1747 // a file, so it should find the same results.
1748 ASSERT_TRUE(base::PathExists(filter_file));
1749 database_.reset(new SafeBrowsingDatabaseNew);
1750 database_->Init(database_filename_);
1751 EXPECT_TRUE(database_->ContainsBrowseUrl(
1752 GURL("http://www.evil.com/malware.html"), &prefix_hits, &cache_hits));
1753 EXPECT_FALSE(database_->ContainsBrowseUrl(
1754 GURL("http://www.good.com/goodware.html"), &prefix_hits, &cache_hits));
1756 // If there is no filter file, the database cannot find malware urls.
1757 base::DeleteFile(filter_file, false);
1758 ASSERT_FALSE(base::PathExists(filter_file));
1759 database_.reset(new SafeBrowsingDatabaseNew);
1760 database_->Init(database_filename_);
1761 EXPECT_FALSE(database_->ContainsBrowseUrl(
1762 GURL("http://www.evil.com/malware.html"), &prefix_hits, &cache_hits));
1763 EXPECT_FALSE(database_->ContainsBrowseUrl(
1764 GURL("http://www.good.com/goodware.html"), &prefix_hits, &cache_hits));
1767 TEST_F(SafeBrowsingDatabaseTest, MalwareIpBlacklist) {
1768 database_.reset();
1769 SafeBrowsingStoreFile* browse_store = new SafeBrowsingStoreFile();
1770 SafeBrowsingStoreFile* ip_blacklist_store = new SafeBrowsingStoreFile();
1771 database_.reset(new SafeBrowsingDatabaseNew(browse_store,
1772 NULL,
1773 NULL,
1774 NULL,
1775 NULL,
1776 NULL,
1777 ip_blacklist_store));
1778 database_->Init(database_filename_);
1779 std::vector<SBListChunkRanges> lists;
1780 ASSERT_TRUE(database_->UpdateStarted(&lists));
1782 // IPv4 prefix match for ::ffff:192.168.1.0/120.
1783 SBChunkList chunks;
1784 SBChunk chunk;
1785 InsertAddChunkFullHash(&chunk, 1, "::ffff:192.168.1.0", 120);
1786 chunks.push_back(chunk);
1787 database_->InsertChunks(safe_browsing_util::kIPBlacklist, chunks);
1789 // IPv4 exact match for ::ffff:192.1.1.1.
1790 chunks.clear();
1791 chunk.hosts.clear();
1792 InsertAddChunkFullHash(&chunk, 2, "::ffff:192.1.1.1", 128);
1793 chunks.push_back(chunk);
1794 database_->InsertChunks(safe_browsing_util::kIPBlacklist, chunks);
1796 // IPv6 exact match for: fe80::31a:a0ff:fe10:786e/128.
1797 chunks.clear();
1798 chunk.hosts.clear();
1799 InsertAddChunkFullHash(&chunk, 3, "fe80::31a:a0ff:fe10:786e", 128);
1800 chunks.push_back(chunk);
1801 database_->InsertChunks(safe_browsing_util::kIPBlacklist, chunks);
1803 // IPv6 prefix match for: 2620:0:1000:3103::/64.
1804 chunks.clear();
1805 chunk.hosts.clear();
1806 InsertAddChunkFullHash(&chunk, 4, "2620:0:1000:3103::", 64);
1807 chunks.push_back(chunk);
1808 database_->InsertChunks(safe_browsing_util::kIPBlacklist, chunks);
1810 // IPv4 prefix match for ::ffff:192.1.122.0/119.
1811 chunks.clear();
1812 chunk.hosts.clear();
1813 InsertAddChunkFullHash(&chunk, 5, "::ffff:192.1.122.0", 119);
1814 chunks.push_back(chunk);
1815 database_->InsertChunks(safe_browsing_util::kIPBlacklist, chunks);
1817 // IPv4 prefix match for ::ffff:192.1.128.0/113.
1818 chunks.clear();
1819 chunk.hosts.clear();
1820 InsertAddChunkFullHash(&chunk, 6, "::ffff:192.1.128.0", 113);
1821 chunks.push_back(chunk);
1822 database_->InsertChunks(safe_browsing_util::kIPBlacklist, chunks);
1824 database_->UpdateFinished(true);
1826 EXPECT_FALSE(database_->ContainsMalwareIP("192.168.0.255"));
1827 EXPECT_TRUE(database_->ContainsMalwareIP("192.168.1.0"));
1828 EXPECT_TRUE(database_->ContainsMalwareIP("192.168.1.255"));
1829 EXPECT_TRUE(database_->ContainsMalwareIP("192.168.1.10"));
1830 EXPECT_TRUE(database_->ContainsMalwareIP("::ffff:192.168.1.2"));
1831 EXPECT_FALSE(database_->ContainsMalwareIP("192.168.2.0"));
1833 EXPECT_FALSE(database_->ContainsMalwareIP("192.1.1.0"));
1834 EXPECT_TRUE(database_->ContainsMalwareIP("192.1.1.1"));
1835 EXPECT_FALSE(database_->ContainsMalwareIP("192.1.1.2"));
1837 EXPECT_FALSE(database_->ContainsMalwareIP(
1838 "2620:0:1000:3102:ffff:ffff:ffff:ffff"));
1839 EXPECT_TRUE(database_->ContainsMalwareIP("2620:0:1000:3103::"));
1840 EXPECT_TRUE(database_->ContainsMalwareIP(
1841 "2620:0:1000:3103:ffff:ffff:ffff:ffff"));
1842 EXPECT_FALSE(database_->ContainsMalwareIP("2620:0:1000:3104::"));
1844 EXPECT_FALSE(database_->ContainsMalwareIP("fe80::21a:a0ff:fe10:786d"));
1845 EXPECT_TRUE(database_->ContainsMalwareIP("fe80::31a:a0ff:fe10:786e"));
1846 EXPECT_FALSE(database_->ContainsMalwareIP("fe80::21a:a0ff:fe10:786f"));
1848 EXPECT_FALSE(database_->ContainsMalwareIP("192.1.121.255"));
1849 EXPECT_TRUE(database_->ContainsMalwareIP("192.1.122.0"));
1850 EXPECT_TRUE(database_->ContainsMalwareIP("::ffff:192.1.122.1"));
1851 EXPECT_TRUE(database_->ContainsMalwareIP("192.1.122.255"));
1852 EXPECT_TRUE(database_->ContainsMalwareIP("192.1.123.0"));
1853 EXPECT_TRUE(database_->ContainsMalwareIP("192.1.123.255"));
1854 EXPECT_FALSE(database_->ContainsMalwareIP("192.1.124.0"));
1856 EXPECT_FALSE(database_->ContainsMalwareIP("192.1.127.255"));
1857 EXPECT_TRUE(database_->ContainsMalwareIP("192.1.128.0"));
1858 EXPECT_TRUE(database_->ContainsMalwareIP("::ffff:192.1.128.1"));
1859 EXPECT_TRUE(database_->ContainsMalwareIP("192.1.128.255"));
1860 EXPECT_TRUE(database_->ContainsMalwareIP("192.1.255.0"));
1861 EXPECT_TRUE(database_->ContainsMalwareIP("192.1.255.255"));
1862 EXPECT_FALSE(database_->ContainsMalwareIP("192.2.0.0"));
1865 TEST_F(SafeBrowsingDatabaseTest, ContainsBrowseURL) {
1866 std::vector<SBListChunkRanges> lists;
1867 ASSERT_TRUE(database_->UpdateStarted(&lists));
1869 // Add a host-level hit.
1871 SBChunkList chunks;
1872 SBChunk chunk;
1873 InsertAddChunkHostPrefix(&chunk, 1, "www.evil.com/");
1874 chunks.push_back(chunk);
1875 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
1878 // Add a specific fullhash.
1879 static const char kWhateverMalware[] = "www.whatever.com/malware.html";
1881 SBChunkList chunks;
1882 SBChunk chunk;
1883 InsertAddChunkHostFullHashes(&chunk, 2, "www.whatever.com/",
1884 kWhateverMalware);
1885 chunks.push_back(chunk);
1886 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
1889 // Add a fullhash which has a prefix collision for a known url.
1890 static const char kExampleFine[] = "www.example.com/fine.html";
1891 static const char kExampleCollision[] =
1892 "www.example.com/3123364814/malware.htm";
1893 ASSERT_EQ(SBPrefixForString(kExampleFine),
1894 SBPrefixForString(kExampleCollision));
1896 SBChunkList chunks;
1897 SBChunk chunk;
1898 InsertAddChunkHostFullHashes(&chunk, 3, "www.example.com/",
1899 kExampleCollision);
1900 chunks.push_back(chunk);
1901 database_->InsertChunks(safe_browsing_util::kMalwareList, chunks);
1904 database_->UpdateFinished(true);
1906 std::vector<SBPrefix> prefix_hits;
1907 std::vector<SBFullHashResult> cache_hits;
1909 // Anything will hit the host prefix.
1910 EXPECT_TRUE(database_->ContainsBrowseUrl(
1911 GURL("http://www.evil.com/malware.html"), &prefix_hits, &cache_hits));
1912 ASSERT_EQ(1U, prefix_hits.size());
1913 EXPECT_EQ(SBPrefixForString("www.evil.com/"), prefix_hits[0]);
1914 EXPECT_TRUE(cache_hits.empty());
1916 // Hit the specific URL prefix.
1917 EXPECT_TRUE(database_->ContainsBrowseUrl(
1918 GURL(std::string("http://") + kWhateverMalware),
1919 &prefix_hits, &cache_hits));
1920 ASSERT_EQ(1U, prefix_hits.size());
1921 EXPECT_EQ(SBPrefixForString(kWhateverMalware), prefix_hits[0]);
1922 EXPECT_TRUE(cache_hits.empty());
1924 // Other URLs at that host are fine.
1925 EXPECT_FALSE(database_->ContainsBrowseUrl(
1926 GURL("http://www.whatever.com/fine.html"), &prefix_hits, &cache_hits));
1927 EXPECT_TRUE(prefix_hits.empty());
1928 EXPECT_TRUE(cache_hits.empty());
1930 // Hit the specific URL full hash.
1931 EXPECT_TRUE(database_->ContainsBrowseUrl(
1932 GURL(std::string("http://") + kExampleCollision),
1933 &prefix_hits, &cache_hits));
1934 ASSERT_EQ(1U, prefix_hits.size());
1935 EXPECT_EQ(SBPrefixForString(kExampleCollision), prefix_hits[0]);
1936 EXPECT_TRUE(cache_hits.empty());
1938 // This prefix collides, but no full hash match.
1939 EXPECT_FALSE(database_->ContainsBrowseUrl(
1940 GURL(std::string("http://") + kExampleFine), &prefix_hits, &cache_hits));