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.
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"
25 using base::TimeDelta
;
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
);
47 // Add a host-level entry.
48 void InsertAddChunkHostPrefix(SBChunk
* chunk
,
50 const std::string
& host_name
) {
51 chunk
->chunk_number
= chunk_number
;
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
62 void InsertAddChunkHostPrefixValue(SBChunk
* chunk
,
64 const SBPrefix
& host_prefix
,
65 const SBPrefix
& url_prefix
) {
66 chunk
->chunk_number
= chunk_number
;
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
,
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
,
90 const std::string
& host_name
,
91 const std::string
& url
) {
92 chunk
->chunk_number
= chunk_number
;
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
,
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;
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
,
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;
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
,
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;
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
159 void InsertSubChunkHostPrefixValue(SBChunk
* chunk
,
162 const SBPrefix
& host_prefix
,
163 const SBPrefix
& url_prefix
) {
164 chunk
->chunk_number
= chunk_number
;
165 chunk
->is_add
= false;
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
,
180 const std::string
& host_name
,
181 const std::string
& url
) {
182 InsertSubChunkHostPrefixValue(chunk
, chunk_number
,
184 SBPrefixForString(host_name
),
185 SBPrefixForString(url
));
188 // Same as InsertSubChunkHostPrefixUrl, but with two urls for prefixes.
189 void InsertSubChunkHost2PrefixUrls(SBChunk
* chunk
,
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;
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
,
212 const std::string
& host_name
,
213 const std::string
& url
) {
214 chunk
->chunk_number
= chunk_number
;
215 chunk
->is_add
= false;
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
{
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
);
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
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());
260 class SafeBrowsingDatabaseTest
: public PlatformTest
{
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
);
269 temp_dir_
.path().AppendASCII("SafeBrowsingTestDatabase");
270 database_
->Init(database_filename_
);
273 virtual void TearDown() {
276 PlatformTest::TearDown();
279 void GetListsInfo(std::vector
<SBListChunkRanges
>* lists
) {
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
,
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
) {
319 InsertAddChunkHostPrefixUrl(&chunk
, 1, "www.evil.com/",
320 "www.evil.com/malware.html");
322 chunks
.push_back(chunk
);
323 std::vector
<SBListChunkRanges
> lists
;
324 ASSERT_TRUE(database_
->UpdateStarted(&lists
));
325 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
328 InsertAddChunkHostPrefixUrl(&chunk
, 2, "www.foo.com/",
329 "www.foo.com/malware.html");
331 chunks
.push_back(chunk
);
332 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
335 InsertAddChunkHostPrefixUrl(&chunk
, 3, "www.whatever.com/",
336 "www.whatever.com/malware.html");
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.
350 InsertSubChunkHostPrefixUrl(&chunk
, 7, 19, "www.subbed.com/",
351 "www.subbed.com/noteveil1.html");
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.
375 InsertAddChunkHostPrefixUrl(&chunk
, 47, "www.evil.com/",
376 "www.evil.com/phishing.html");
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.
384 InsertSubChunkHostPrefixUrl(&chunk
, 200, 1999, "www.phishy.com/",
385 "www.phishy.com/notevil1.html");
387 chunks
.push_back(chunk
);
388 database_
->InsertChunks(safe_browsing_util::kPhishingList
, chunks
);
391 InsertSubChunkHostPrefixUrl(&chunk
, 201, 1999, "www.phishy2.com/",
392 "www.phishy2.com/notevil1.html");
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
) {
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
,
421 download_whitelist_store
,
422 extension_blacklist_store
,
424 ip_blacklist_store
));
425 database_
->Init(database_filename_
);
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
);
439 InsertAddChunkHostPrefixUrl(&chunk
, 2, "www.foo.com/",
440 "www.foo.com/malware.html");
442 chunks
.push_back(chunk
);
443 database_
->InsertChunks(safe_browsing_util::kPhishingList
, chunks
);
446 InsertAddChunkHostPrefixUrl(&chunk
, 3, "www.whatever.com/",
447 "www.whatever.com/download.html");
449 chunks
.push_back(chunk
);
450 database_
->InsertChunks(safe_browsing_util::kBinUrlList
, chunks
);
453 InsertAddChunkHostFullHashes(&chunk
, 5, "www.forwhitelist.com/",
454 "www.forwhitelist.com/a.html");
456 chunks
.push_back(chunk
);
457 database_
->InsertChunks(safe_browsing_util::kCsdWhiteList
, chunks
);
460 InsertAddChunkHostFullHashes(&chunk
, 6, "www.download.com/",
461 "www.download.com/");
464 chunks
.push_back(chunk
);
465 database_
->InsertChunks(safe_browsing_util::kDownloadWhiteList
, chunks
);
468 InsertAddChunkHostFullHashes(&chunk
, 8,
469 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
470 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
473 chunks
.push_back(chunk
);
474 database_
->InsertChunks(safe_browsing_util::kExtensionBlacklist
, chunks
);
477 InsertAddChunkFullHash(&chunk
, 9, "::ffff:192.168.1.0", 120);
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());
512 // Checks database reading and writing for browse.
513 TEST_F(SafeBrowsingDatabaseTest
, BrowseDatabase
) {
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
);
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");
534 chunks
.push_back(chunk
);
535 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
537 // and a chunk with an IP-based host
539 InsertAddChunkHostPrefixUrl(&chunk
, 3, "192.168.0.1/",
540 "192.168.0.1/malware.html");
542 chunks
.push_back(chunk
);
543 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
545 // A chunk with a full hash.
547 InsertAddChunkHostFullHashes(&chunk
, 7, "www.evil.com/",
548 "www.evil.com/evil.html");
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
604 InsertAddChunkHost2PrefixUrls(&chunk
, 1, "www.evil.com/",
605 "www.evil.com/phishing.html",
606 "www.evil.com/malware.html");
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.
621 InsertSubChunkHostPrefixUrl(&chunk
, 4, 2, "www.evil.com/",
622 "www.evil.com/notevil1.html");
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
659 InsertSubChunkHostPrefixUrl(&chunk
, 4, 2, "www.evil.com/",
660 "www.evil.com/notevil1.html");
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.
698 InsertAddChunkHostPrefixUrl(&chunk
, 44, "www.redherring.com/",
699 "www.redherring.com/index.html");
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.
721 InsertSubChunkHost2PrefixUrls(&chunk
, 5, 10,
722 "www.notevilanymore.com/",
723 "www.notevilanymore.com/index.html",
724 "www.notevilanymore.com/good.html");
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"),
736 // Now insert the tardy add chunk and we don't expect them to appear
737 // in database because of the previous sub chunk.
739 InsertAddChunkHost2PrefixUrls(&chunk
, 10, "www.notevilanymore.com/",
740 "www.notevilanymore.com/index.html",
741 "www.notevilanymore.com/good.html");
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"),
753 EXPECT_FALSE(database_
->ContainsBrowseUrl(
754 GURL("http://www.notevilanymore.com/good.html"),
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
) {
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");
790 chunks
.push_back(chunk
);
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());
811 empty_chunk
.chunk_number
= 19;
812 empty_chunk
.is_add
= true;
814 chunks
.push_back(empty_chunk
);
815 ASSERT_TRUE(database_
->UpdateStarted(&lists
));
816 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
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");
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() {
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")));
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")));
945 // Test removing a prefix via a sub chunk.
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());
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());
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());
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
;
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
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();
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();
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");
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();
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();
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");
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();
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
));
1126 InsertAddChunkHostPrefixUrl(&chunk
, 21, "www.example.com/",
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
),
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
1163 base::MessageLoop loop
;
1164 SafeBrowsingStoreFile
* store
= new SafeBrowsingStoreFile();
1165 database_
.reset(new SafeBrowsingDatabaseNew(store
, NULL
, NULL
, 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.
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
);
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+");
1194 ASSERT_NE(-1, fseek(fp
, -8, SEEK_END
));
1195 for (size_t i
= 0; i
< 8; ++i
) {
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_
));
1229 // Checks database reading and writing.
1230 TEST_F(SafeBrowsingDatabaseTest
, ContainsDownloadUrl
) {
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
,
1238 csd_whitelist_store
,
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";
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.
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.
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.
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.
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]);
1334 // Checks that the whitelists are handled properly.
1335 TEST_F(SafeBrowsingDatabaseTest
, Whitelists
) {
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
,
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
,
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
;
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
,
1404 database_
->InsertChunks(safe_browsing_util::kDownloadWhiteList
,
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
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.
1472 download_chunks
.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
,
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.
1511 download_chunks
.clear();
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
,
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"));
1562 // Test to make sure we could insert chunk list that
1563 // contains entries for the same host.
1564 TEST_F(SafeBrowsingDatabaseTest
, SameHostEntriesOkay
) {
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");
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");
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");
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");
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
1656 TEST_F(SafeBrowsingDatabaseTest
, EmptyUpdate
) {
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");
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");
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
1717 TEST_F(SafeBrowsingDatabaseTest
, FilterFile
) {
1718 // Create a database with trivial example data and write it out.
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");
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
) {
1769 SafeBrowsingStoreFile
* browse_store
= new SafeBrowsingStoreFile();
1770 SafeBrowsingStoreFile
* ip_blacklist_store
= new SafeBrowsingStoreFile();
1771 database_
.reset(new SafeBrowsingDatabaseNew(browse_store
,
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.
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.
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.
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.
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.
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.
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.
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";
1883 InsertAddChunkHostFullHashes(&chunk
, 2, "www.whatever.com/",
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
));
1898 InsertAddChunkHostFullHashes(&chunk
, 3, "www.example.com/",
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
));