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"
28 SBPrefix
SBPrefixForString(const std::string
& str
) {
29 return SBFullHashForString(str
).prefix
;
32 std::string
HashedIpPrefix(const std::string
& ip_prefix
, size_t prefix_size
) {
33 net::IPAddressNumber ip_number
;
34 EXPECT_TRUE(net::ParseIPLiteralToNumber(ip_prefix
, &ip_number
));
35 EXPECT_EQ(net::kIPv6AddressSize
, ip_number
.size());
36 const std::string hashed_ip_prefix
= base::SHA1HashString(
37 net::IPAddressToPackedString(ip_number
));
38 std::string
hash(crypto::kSHA256Length
, '\0');
39 hash
.replace(0, hashed_ip_prefix
.size(), hashed_ip_prefix
);
40 hash
[base::kSHA1Length
] = static_cast<char>(prefix_size
);
44 // Add a host-level entry.
45 void InsertAddChunkHostPrefix(SBChunk
* chunk
,
47 const std::string
& host_name
) {
48 chunk
->chunk_number
= chunk_number
;
51 host
.host
= SBPrefixForString(host_name
);
52 host
.entry
= SBEntry::Create(SBEntry::ADD_PREFIX
, 0);
53 host
.entry
->set_chunk_id(chunk
->chunk_number
);
54 chunk
->hosts
.push_back(host
);
57 // Same as InsertAddChunkHostPrefixUrl, but with pre-computed
59 void InsertAddChunkHostPrefixValue(SBChunk
* chunk
,
61 const SBPrefix
& host_prefix
,
62 const SBPrefix
& url_prefix
) {
63 chunk
->chunk_number
= chunk_number
;
66 host
.host
= host_prefix
;
67 host
.entry
= SBEntry::Create(SBEntry::ADD_PREFIX
, 1);
68 host
.entry
->set_chunk_id(chunk
->chunk_number
);
69 host
.entry
->SetPrefixAt(0, url_prefix
);
70 chunk
->hosts
.push_back(host
);
73 // A helper function that appends one AddChunkHost to chunk with
74 // one url for prefix.
75 void InsertAddChunkHostPrefixUrl(SBChunk
* chunk
,
77 const std::string
& host_name
,
78 const std::string
& url
) {
79 InsertAddChunkHostPrefixValue(chunk
, chunk_number
,
80 SBPrefixForString(host_name
),
81 SBPrefixForString(url
));
84 // Same as InsertAddChunkHostPrefixUrl, but with full hashes.
85 void InsertAddChunkHostFullHashes(SBChunk
* chunk
,
87 const std::string
& host_name
,
88 const std::string
& url
) {
89 chunk
->chunk_number
= chunk_number
;
92 host
.host
= SBPrefixForString(host_name
);
93 host
.entry
= SBEntry::Create(SBEntry::ADD_FULL_HASH
, 1);
94 host
.entry
->set_chunk_id(chunk
->chunk_number
);
95 host
.entry
->SetFullHashAt(0, SBFullHashForString(url
));
96 chunk
->hosts
.push_back(host
);
99 // TODO(shess): This sounds like something to insert a full-hash chunk, but it's
100 // actually specific to IP blacklist.
101 void InsertAddChunkFullHash(SBChunk
* chunk
,
103 const std::string
& ip_str
,
104 size_t prefix_size
) {
105 const std::string full_hash_str
= HashedIpPrefix(ip_str
, prefix_size
);
106 EXPECT_EQ(sizeof(SBFullHash
), full_hash_str
.size());
107 SBFullHash full_hash
;
108 std::memcpy(&(full_hash
.full_hash
), full_hash_str
.data(), sizeof(SBFullHash
));
110 chunk
->chunk_number
= chunk_number
;
111 chunk
->is_add
= true;
113 host
.host
= full_hash
.prefix
;
114 host
.entry
= SBEntry::Create(SBEntry::ADD_FULL_HASH
, 1);
115 host
.entry
->set_chunk_id(chunk
->chunk_number
);
116 host
.entry
->SetFullHashAt(0, full_hash
);
117 chunk
->hosts
.push_back(host
);
120 // Same as InsertAddChunkHostPrefixUrl, but with two urls for prefixes.
121 void InsertAddChunkHost2PrefixUrls(SBChunk
* chunk
,
123 const std::string
& host_name
,
124 const std::string
& url1
,
125 const std::string
& url2
) {
126 chunk
->chunk_number
= chunk_number
;
127 chunk
->is_add
= true;
129 host
.host
= SBPrefixForString(host_name
);
130 host
.entry
= SBEntry::Create(SBEntry::ADD_PREFIX
, 2);
131 host
.entry
->set_chunk_id(chunk
->chunk_number
);
132 host
.entry
->SetPrefixAt(0, SBPrefixForString(url1
));
133 host
.entry
->SetPrefixAt(1, SBPrefixForString(url2
));
134 chunk
->hosts
.push_back(host
);
137 // Same as InsertAddChunkHost2PrefixUrls, but with full hashes.
138 void InsertAddChunkHost2FullHashes(SBChunk
* chunk
,
140 const std::string
& host_name
,
141 const std::string
& url1
,
142 const std::string
& url2
) {
143 chunk
->chunk_number
= chunk_number
;
144 chunk
->is_add
= true;
146 host
.host
= SBPrefixForString(host_name
);
147 host
.entry
= SBEntry::Create(SBEntry::ADD_FULL_HASH
, 2);
148 host
.entry
->set_chunk_id(chunk
->chunk_number
);
149 host
.entry
->SetFullHashAt(0, SBFullHashForString(url1
));
150 host
.entry
->SetFullHashAt(1, SBFullHashForString(url2
));
151 chunk
->hosts
.push_back(host
);
154 // Same as InsertSubChunkHostPrefixUrl, but with pre-computed
156 void InsertSubChunkHostPrefixValue(SBChunk
* chunk
,
159 const SBPrefix
& host_prefix
,
160 const SBPrefix
& url_prefix
) {
161 chunk
->chunk_number
= chunk_number
;
162 chunk
->is_add
= false;
164 host
.host
= host_prefix
;
165 host
.entry
= SBEntry::Create(SBEntry::SUB_PREFIX
, 1);
166 host
.entry
->set_chunk_id(chunk
->chunk_number
);
167 host
.entry
->SetChunkIdAtPrefix(0, chunk_id_to_sub
);
168 host
.entry
->SetPrefixAt(0, url_prefix
);
169 chunk
->hosts
.push_back(host
);
172 // A helper function that adds one SubChunkHost to chunk with
173 // one url for prefix.
174 void InsertSubChunkHostPrefixUrl(SBChunk
* chunk
,
177 const std::string
& host_name
,
178 const std::string
& url
) {
179 InsertSubChunkHostPrefixValue(chunk
, chunk_number
,
181 SBPrefixForString(host_name
),
182 SBPrefixForString(url
));
185 // Same as InsertSubChunkHostPrefixUrl, but with two urls for prefixes.
186 void InsertSubChunkHost2PrefixUrls(SBChunk
* chunk
,
189 const std::string
& host_name
,
190 const std::string
& url1
,
191 const std::string
& url2
) {
192 chunk
->chunk_number
= chunk_number
;
193 chunk
->is_add
= false;
195 host
.host
= SBPrefixForString(host_name
);
196 host
.entry
= SBEntry::Create(SBEntry::SUB_PREFIX
, 2);
197 host
.entry
->set_chunk_id(chunk
->chunk_number
);
198 host
.entry
->SetPrefixAt(0, SBPrefixForString(url1
));
199 host
.entry
->SetChunkIdAtPrefix(0, chunk_id_to_sub
);
200 host
.entry
->SetPrefixAt(1, SBPrefixForString(url2
));
201 host
.entry
->SetChunkIdAtPrefix(1, chunk_id_to_sub
);
202 chunk
->hosts
.push_back(host
);
205 // Same as InsertSubChunkHost2PrefixUrls, but with full hashes.
206 void InsertSubChunkHostFullHash(SBChunk
* chunk
,
209 const std::string
& host_name
,
210 const std::string
& url
) {
211 chunk
->chunk_number
= chunk_number
;
212 chunk
->is_add
= false;
214 host
.host
= SBPrefixForString(host_name
);
215 host
.entry
= SBEntry::Create(SBEntry::SUB_FULL_HASH
, 2);
216 host
.entry
->set_chunk_id(chunk
->chunk_number
);
217 host
.entry
->SetFullHashAt(0, SBFullHashForString(url
));
218 host
.entry
->SetChunkIdAtPrefix(0, chunk_id_to_sub
);
219 chunk
->hosts
.push_back(host
);
222 // Prevent DCHECK from killing tests.
223 // TODO(shess): Pawel disputes the use of this, so the test which uses
224 // it is DISABLED. http://crbug.com/56448
225 class ScopedLogMessageIgnorer
{
227 ScopedLogMessageIgnorer() {
228 logging::SetLogMessageHandler(&LogMessageIgnorer
);
230 ~ScopedLogMessageIgnorer() {
231 // TODO(shess): Would be better to verify whether anyone else
232 // changed it, and then restore it to the previous value.
233 logging::SetLogMessageHandler(NULL
);
237 static bool LogMessageIgnorer(int severity
, const char* file
, int line
,
238 size_t message_start
, const std::string
& str
) {
239 // Intercept FATAL, strip the stack backtrace, and log it without
241 if (severity
== logging::LOG_FATAL
) {
242 size_t newline
= str
.find('\n');
243 if (newline
!= std::string::npos
) {
244 const std::string msg
= str
.substr(0, newline
+ 1);
245 fprintf(stderr
, "%s", msg
.c_str());
257 class SafeBrowsingDatabaseTest
: public PlatformTest
{
259 virtual void SetUp() {
260 PlatformTest::SetUp();
262 // Setup a database in a temporary directory.
263 ASSERT_TRUE(temp_dir_
.CreateUniqueTempDir());
264 database_
.reset(new SafeBrowsingDatabaseNew
);
266 temp_dir_
.path().AppendASCII("SafeBrowsingTestDatabase");
267 database_
->Init(database_filename_
);
270 virtual void TearDown() {
273 PlatformTest::TearDown();
276 void GetListsInfo(std::vector
<SBListChunkRanges
>* lists
) {
278 EXPECT_TRUE(database_
->UpdateStarted(lists
));
279 database_
->UpdateFinished(true);
282 // Helper function to do an AddDel or SubDel command.
283 void DelChunk(const std::string
& list
,
286 std::vector
<SBChunkDelete
> deletes
;
287 SBChunkDelete chunk_delete
;
288 chunk_delete
.list_name
= list
;
289 chunk_delete
.is_sub_del
= is_sub_del
;
290 chunk_delete
.chunk_del
.push_back(ChunkRange(chunk_id
));
291 deletes
.push_back(chunk_delete
);
292 database_
->DeleteChunks(deletes
);
295 void AddDelChunk(const std::string
& list
, int chunk_id
) {
296 DelChunk(list
, chunk_id
, false);
299 void SubDelChunk(const std::string
& list
, int chunk_id
) {
300 DelChunk(list
, chunk_id
, true);
303 // Utility function for setting up the database for the caching test.
304 void PopulateDatabaseForCacheTest();
306 scoped_ptr
<SafeBrowsingDatabaseNew
> database_
;
307 base::FilePath database_filename_
;
308 base::ScopedTempDir temp_dir_
;
311 // Tests retrieving list name information.
312 TEST_F(SafeBrowsingDatabaseTest
, ListNameForBrowse
) {
316 InsertAddChunkHostPrefixUrl(&chunk
, 1, "www.evil.com/",
317 "www.evil.com/malware.html");
319 chunks
.push_back(chunk
);
320 std::vector
<SBListChunkRanges
> lists
;
321 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
322 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
325 InsertAddChunkHostPrefixUrl(&chunk
, 2, "www.foo.com/",
326 "www.foo.com/malware.html");
328 chunks
.push_back(chunk
);
329 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
332 InsertAddChunkHostPrefixUrl(&chunk
, 3, "www.whatever.com/",
333 "www.whatever.com/malware.html");
335 chunks
.push_back(chunk
);
336 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
337 database_
->UpdateFinished(true);
339 GetListsInfo(&lists
);
340 EXPECT_TRUE(lists
[0].name
== safe_browsing_util::kMalwareList
);
341 EXPECT_EQ(lists
[0].adds
, "1-3");
342 EXPECT_TRUE(lists
[0].subs
.empty());
344 // Insert a malware sub chunk.
346 InsertSubChunkHostPrefixUrl(&chunk
, 7, 19, "www.subbed.com/",
347 "www.subbed.com/noteveil1.html");
349 chunks
.push_back(chunk
);
351 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
352 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
353 database_
->UpdateFinished(true);
355 GetListsInfo(&lists
);
356 EXPECT_TRUE(lists
[0].name
== safe_browsing_util::kMalwareList
);
357 EXPECT_EQ(lists
[0].adds
, "1-3");
358 EXPECT_EQ(lists
[0].subs
, "7");
359 if (lists
.size() == 2) {
360 // Old style database won't have the second entry since it creates the lists
361 // when it receives an update containing that list. The filter-based
362 // database has these values hard coded.
363 EXPECT_TRUE(lists
[1].name
== safe_browsing_util::kPhishingList
);
364 EXPECT_TRUE(lists
[1].adds
.empty());
365 EXPECT_TRUE(lists
[1].subs
.empty());
368 // Add a phishing add chunk.
370 InsertAddChunkHostPrefixUrl(&chunk
, 47, "www.evil.com/",
371 "www.evil.com/phishing.html");
373 chunks
.push_back(chunk
);
374 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
375 database_
->InsertChunks(safe_browsing_util::kPhishingList
, chunks
);
377 // Insert some phishing sub chunks.
379 InsertSubChunkHostPrefixUrl(&chunk
, 200, 1999, "www.phishy.com/",
380 "www.phishy.com/notevil1.html");
382 chunks
.push_back(chunk
);
383 database_
->InsertChunks(safe_browsing_util::kPhishingList
, chunks
);
386 InsertSubChunkHostPrefixUrl(&chunk
, 201, 1999, "www.phishy2.com/",
387 "www.phishy2.com/notevil1.html");
389 chunks
.push_back(chunk
);
390 database_
->InsertChunks(safe_browsing_util::kPhishingList
, chunks
);
391 database_
->UpdateFinished(true);
393 GetListsInfo(&lists
);
394 EXPECT_TRUE(lists
[0].name
== safe_browsing_util::kMalwareList
);
395 EXPECT_EQ(lists
[0].adds
, "1-3");
396 EXPECT_EQ(lists
[0].subs
, "7");
397 EXPECT_TRUE(lists
[1].name
== safe_browsing_util::kPhishingList
);
398 EXPECT_EQ(lists
[1].adds
, "47");
399 EXPECT_EQ(lists
[1].subs
, "200-201");
402 TEST_F(SafeBrowsingDatabaseTest
, ListNameForBrowseAndDownload
) {
404 base::MessageLoop loop
;
405 SafeBrowsingStoreFile
* browse_store
= new SafeBrowsingStoreFile();
406 SafeBrowsingStoreFile
* download_store
= new SafeBrowsingStoreFile();
407 SafeBrowsingStoreFile
* csd_whitelist_store
= new SafeBrowsingStoreFile();
408 SafeBrowsingStoreFile
* download_whitelist_store
= new SafeBrowsingStoreFile();
409 SafeBrowsingStoreFile
* extension_blacklist_store
=
410 new SafeBrowsingStoreFile();
411 SafeBrowsingStoreFile
* ip_blacklist_store
= new SafeBrowsingStoreFile();
412 database_
.reset(new SafeBrowsingDatabaseNew(browse_store
,
415 download_whitelist_store
,
416 extension_blacklist_store
,
418 ip_blacklist_store
));
419 database_
->Init(database_filename_
);
424 // Insert malware, phish, binurl and bindownload add chunks.
425 InsertAddChunkHostPrefixUrl(&chunk
, 1, "www.evil.com/",
426 "www.evil.com/malware.html");
427 chunks
.push_back(chunk
);
428 std::vector
<SBListChunkRanges
> lists
;
429 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
430 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
433 InsertAddChunkHostPrefixUrl(&chunk
, 2, "www.foo.com/",
434 "www.foo.com/malware.html");
436 chunks
.push_back(chunk
);
437 database_
->InsertChunks(safe_browsing_util::kPhishingList
, chunks
);
440 InsertAddChunkHostPrefixUrl(&chunk
, 3, "www.whatever.com/",
441 "www.whatever.com/download.html");
443 chunks
.push_back(chunk
);
444 database_
->InsertChunks(safe_browsing_util::kBinUrlList
, chunks
);
447 InsertAddChunkHostFullHashes(&chunk
, 5, "www.forwhitelist.com/",
448 "www.forwhitelist.com/a.html");
450 chunks
.push_back(chunk
);
451 database_
->InsertChunks(safe_browsing_util::kCsdWhiteList
, chunks
);
454 InsertAddChunkHostFullHashes(&chunk
, 6, "www.download.com/",
455 "www.download.com/");
458 chunks
.push_back(chunk
);
459 database_
->InsertChunks(safe_browsing_util::kDownloadWhiteList
, chunks
);
462 InsertAddChunkHostFullHashes(&chunk
, 8,
463 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
464 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
467 chunks
.push_back(chunk
);
468 database_
->InsertChunks(safe_browsing_util::kExtensionBlacklist
, chunks
);
471 InsertAddChunkFullHash(&chunk
, 9, "::ffff:192.168.1.0", 120);
474 chunks
.push_back(chunk
);
475 database_
->InsertChunks(safe_browsing_util::kIPBlacklist
, chunks
);
477 database_
->UpdateFinished(true);
479 GetListsInfo(&lists
);
480 ASSERT_EQ(7U, lists
.size());
481 EXPECT_TRUE(lists
[0].name
== safe_browsing_util::kMalwareList
);
482 EXPECT_EQ(lists
[0].adds
, "1");
483 EXPECT_TRUE(lists
[0].subs
.empty());
484 EXPECT_TRUE(lists
[1].name
== safe_browsing_util::kPhishingList
);
485 EXPECT_EQ(lists
[1].adds
, "2");
486 EXPECT_TRUE(lists
[1].subs
.empty());
487 EXPECT_TRUE(lists
[2].name
== safe_browsing_util::kBinUrlList
);
488 EXPECT_EQ(lists
[2].adds
, "3");
489 EXPECT_TRUE(lists
[2].subs
.empty());
490 EXPECT_TRUE(lists
[3].name
== safe_browsing_util::kCsdWhiteList
);
491 EXPECT_EQ(lists
[3].adds
, "5");
492 EXPECT_TRUE(lists
[3].subs
.empty());
493 EXPECT_TRUE(lists
[4].name
== safe_browsing_util::kDownloadWhiteList
);
494 EXPECT_EQ(lists
[4].adds
, "6");
495 EXPECT_TRUE(lists
[4].subs
.empty());
496 EXPECT_TRUE(lists
[5].name
== safe_browsing_util::kExtensionBlacklist
);
497 EXPECT_EQ(lists
[5].adds
, "8");
498 EXPECT_TRUE(lists
[5].subs
.empty());
499 EXPECT_TRUE(lists
[6].name
== safe_browsing_util::kIPBlacklist
);
500 EXPECT_EQ(lists
[6].adds
, "9");
501 EXPECT_TRUE(lists
[6].subs
.empty());
506 // Checks database reading and writing for browse.
507 TEST_F(SafeBrowsingDatabaseTest
, BrowseDatabase
) {
511 // Add a simple chunk with one hostkey.
512 InsertAddChunkHost2PrefixUrls(&chunk
, 1, "www.evil.com/",
513 "www.evil.com/phishing.html",
514 "www.evil.com/malware.html");
515 chunks
.push_back(chunk
);
516 std::vector
<SBListChunkRanges
> lists
;
517 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
518 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
521 InsertAddChunkHost2PrefixUrls(&chunk
, 2, "www.evil.com/",
522 "www.evil.com/notevil1.html",
523 "www.evil.com/notevil2.html");
524 InsertAddChunkHost2PrefixUrls(&chunk
, 2, "www.good.com/",
525 "www.good.com/good1.html",
526 "www.good.com/good2.html");
528 chunks
.push_back(chunk
);
529 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
531 // and a chunk with an IP-based host
533 InsertAddChunkHostPrefixUrl(&chunk
, 3, "192.168.0.1/",
534 "192.168.0.1/malware.html");
536 chunks
.push_back(chunk
);
537 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
539 // A chunk with a full hash.
541 InsertAddChunkHostFullHashes(&chunk
, 7, "www.evil.com/",
542 "www.evil.com/evil.html");
544 chunks
.push_back(chunk
);
545 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
547 database_
->UpdateFinished(true);
549 // Make sure they were added correctly.
550 GetListsInfo(&lists
);
551 EXPECT_TRUE(lists
[0].name
== safe_browsing_util::kMalwareList
);
552 EXPECT_EQ(lists
[0].adds
, "1-3,7");
553 EXPECT_TRUE(lists
[0].subs
.empty());
555 const Time now
= Time::Now();
556 std::vector
<SBFullHashResult
> cached_hashes
;
557 std::vector
<SBPrefix
> prefix_hits
;
558 EXPECT_TRUE(database_
->ContainsBrowseUrl(
559 GURL("http://www.evil.com/phishing.html"),
560 &prefix_hits
, &cached_hashes
, now
));
561 EXPECT_EQ(prefix_hits
[0], SBPrefixForString("www.evil.com/phishing.html"));
562 EXPECT_EQ(prefix_hits
.size(), 1U);
564 EXPECT_TRUE(database_
->ContainsBrowseUrl(
565 GURL("http://www.evil.com/malware.html"),
566 &prefix_hits
, &cached_hashes
, now
));
568 EXPECT_TRUE(database_
->ContainsBrowseUrl(
569 GURL("http://www.evil.com/notevil1.html"),
570 &prefix_hits
, &cached_hashes
, now
));
572 EXPECT_TRUE(database_
->ContainsBrowseUrl(
573 GURL("http://www.evil.com/notevil2.html"),
574 &prefix_hits
, &cached_hashes
, now
));
576 EXPECT_TRUE(database_
->ContainsBrowseUrl(
577 GURL("http://www.good.com/good1.html"),
578 &prefix_hits
, &cached_hashes
, now
));
580 EXPECT_TRUE(database_
->ContainsBrowseUrl(
581 GURL("http://www.good.com/good2.html"),
582 &prefix_hits
, &cached_hashes
, now
));
584 EXPECT_TRUE(database_
->ContainsBrowseUrl(
585 GURL("http://192.168.0.1/malware.html"),
586 &prefix_hits
, &cached_hashes
, now
));
588 EXPECT_FALSE(database_
->ContainsBrowseUrl(
589 GURL("http://www.evil.com/"),
590 &prefix_hits
, &cached_hashes
, now
));
591 EXPECT_TRUE(prefix_hits
.empty());
593 EXPECT_FALSE(database_
->ContainsBrowseUrl(
594 GURL("http://www.evil.com/robots.txt"),
595 &prefix_hits
, &cached_hashes
, now
));
597 EXPECT_TRUE(database_
->ContainsBrowseUrl(
598 GURL("http://www.evil.com/evil.html"),
599 &prefix_hits
, &cached_hashes
, now
));
600 ASSERT_EQ(1U, prefix_hits
.size());
601 EXPECT_EQ(prefix_hits
[0], SBPrefixForString("www.evil.com/evil.html"));
603 // Attempt to re-add the first chunk (should be a no-op).
604 // see bug: http://code.google.com/p/chromium/issues/detail?id=4522
606 InsertAddChunkHost2PrefixUrls(&chunk
, 1, "www.evil.com/",
607 "www.evil.com/phishing.html",
608 "www.evil.com/malware.html");
610 chunks
.push_back(chunk
);
611 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
612 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
613 database_
->UpdateFinished(true);
615 GetListsInfo(&lists
);
616 EXPECT_TRUE(lists
[0].name
== safe_browsing_util::kMalwareList
);
617 EXPECT_EQ(lists
[0].adds
, "1-3,7");
618 EXPECT_TRUE(lists
[0].subs
.empty());
620 // Test removing a single prefix from the add chunk.
622 InsertSubChunkHostPrefixUrl(&chunk
, 4, 2, "www.evil.com/",
623 "www.evil.com/notevil1.html");
625 chunks
.push_back(chunk
);
626 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
627 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
629 database_
->UpdateFinished(true);
631 EXPECT_TRUE(database_
->ContainsBrowseUrl(
632 GURL("http://www.evil.com/phishing.html"),
633 &prefix_hits
, &cached_hashes
, now
));
634 EXPECT_EQ(prefix_hits
[0], SBPrefixForString("www.evil.com/phishing.html"));
635 EXPECT_EQ(prefix_hits
.size(), 1U);
637 EXPECT_FALSE(database_
->ContainsBrowseUrl(
638 GURL("http://www.evil.com/notevil1.html"),
639 &prefix_hits
, &cached_hashes
, now
));
640 EXPECT_TRUE(prefix_hits
.empty());
642 EXPECT_TRUE(database_
->ContainsBrowseUrl(
643 GURL("http://www.evil.com/notevil2.html"),
644 &prefix_hits
, &cached_hashes
, now
));
646 EXPECT_TRUE(database_
->ContainsBrowseUrl(
647 GURL("http://www.good.com/good1.html"),
648 &prefix_hits
, &cached_hashes
, now
));
650 EXPECT_TRUE(database_
->ContainsBrowseUrl(
651 GURL("http://www.good.com/good2.html"),
652 &prefix_hits
, &cached_hashes
, now
));
654 GetListsInfo(&lists
);
655 EXPECT_TRUE(lists
[0].name
== safe_browsing_util::kMalwareList
);
656 EXPECT_EQ(lists
[0].subs
, "4");
658 // Test the same sub chunk again. This should be a no-op.
659 // see bug: http://code.google.com/p/chromium/issues/detail?id=4522
661 InsertSubChunkHostPrefixUrl(&chunk
, 4, 2, "www.evil.com/",
662 "www.evil.com/notevil1.html");
664 chunks
.push_back(chunk
);
666 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
667 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
668 database_
->UpdateFinished(true);
670 GetListsInfo(&lists
);
671 EXPECT_TRUE(lists
[0].name
== safe_browsing_util::kMalwareList
);
672 EXPECT_EQ(lists
[0].subs
, "4");
674 // Test removing all the prefixes from an add chunk.
675 EXPECT_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"),
681 &prefix_hits
, &cached_hashes
, now
));
683 EXPECT_FALSE(database_
->ContainsBrowseUrl(
684 GURL("http://www.good.com/good1.html"),
685 &prefix_hits
, &cached_hashes
, now
));
687 EXPECT_FALSE(database_
->ContainsBrowseUrl(
688 GURL("http://www.good.com/good2.html"),
689 &prefix_hits
, &cached_hashes
, now
));
691 GetListsInfo(&lists
);
692 EXPECT_TRUE(lists
[0].name
== safe_browsing_util::kMalwareList
);
693 EXPECT_EQ(lists
[0].adds
, "1,3,7");
694 EXPECT_EQ(lists
[0].subs
, "4");
696 // The adddel command exposed a bug in the transaction code where any
697 // transaction after it would fail. Add a dummy entry and remove it to
698 // make sure the transcation works fine.
700 InsertAddChunkHostPrefixUrl(&chunk
, 44, "www.redherring.com/",
701 "www.redherring.com/index.html");
703 chunks
.push_back(chunk
);
704 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
705 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
707 // Now remove the dummy entry. If there are any problems with the
708 // transactions, asserts will fire.
709 AddDelChunk(safe_browsing_util::kMalwareList
, 44);
711 // Test the subdel command.
712 SubDelChunk(safe_browsing_util::kMalwareList
, 4);
713 database_
->UpdateFinished(true);
715 GetListsInfo(&lists
);
716 EXPECT_TRUE(lists
[0].name
== safe_browsing_util::kMalwareList
);
717 EXPECT_EQ(lists
[0].adds
, "1,3,7");
718 EXPECT_EQ(lists
[0].subs
, "");
720 // Test a sub command coming in before the add.
722 InsertSubChunkHost2PrefixUrls(&chunk
, 5, 10,
723 "www.notevilanymore.com/",
724 "www.notevilanymore.com/index.html",
725 "www.notevilanymore.com/good.html");
727 chunks
.push_back(chunk
);
728 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
729 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
730 database_
->UpdateFinished(true);
732 EXPECT_FALSE(database_
->ContainsBrowseUrl(
733 GURL("http://www.notevilanymore.com/index.html"),
734 &prefix_hits
, &cached_hashes
, now
));
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 EXPECT_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
, &cached_hashes
, now
));
752 EXPECT_FALSE(database_
->ContainsBrowseUrl(
753 GURL("http://www.notevilanymore.com/good.html"),
754 &prefix_hits
, &cached_hashes
, now
));
756 // Reset and reload the database. The database will rely on the prefix set.
757 database_
.reset(new SafeBrowsingDatabaseNew
);
758 database_
->Init(database_filename_
);
760 // Check that a prefix still hits.
761 EXPECT_TRUE(database_
->ContainsBrowseUrl(
762 GURL("http://www.evil.com/phishing.html"),
763 &prefix_hits
, &cached_hashes
, now
));
764 EXPECT_EQ(prefix_hits
[0], SBPrefixForString("www.evil.com/phishing.html"));
765 EXPECT_EQ(prefix_hits
.size(), 1U);
767 // Also check that it's not just always returning true in this case.
768 EXPECT_FALSE(database_
->ContainsBrowseUrl(
769 GURL("http://www.evil.com/"),
770 &prefix_hits
, &cached_hashes
, now
));
772 // Check that the full hash is still present.
773 EXPECT_TRUE(database_
->ContainsBrowseUrl(
774 GURL("http://www.evil.com/evil.html"),
775 &prefix_hits
, &cached_hashes
, now
));
776 ASSERT_EQ(1U, prefix_hits
.size());
777 EXPECT_EQ(prefix_hits
[0], SBPrefixForString("www.evil.com/evil.html"));
781 // Test adding zero length chunks to the database.
782 TEST_F(SafeBrowsingDatabaseTest
, ZeroSizeChunk
) {
786 // Populate with a couple of normal chunks.
787 InsertAddChunkHost2PrefixUrls(&chunk
, 1, "www.test.com/",
788 "www.test.com/test1.html",
789 "www.test.com/test2.html");
791 chunks
.push_back(chunk
);
794 InsertAddChunkHost2PrefixUrls(&chunk
, 10, "www.random.com/",
795 "www.random.com/random1.html",
796 "www.random.com/random2.html");
797 chunks
.push_back(chunk
);
799 std::vector
<SBListChunkRanges
> lists
;
800 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
801 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
802 database_
->UpdateFinished(true);
804 // Add an empty ADD and SUB chunk.
805 GetListsInfo(&lists
);
806 EXPECT_EQ(lists
[0].adds
, "1,10");
809 empty_chunk
.chunk_number
= 19;
810 empty_chunk
.is_add
= true;
812 chunks
.push_back(empty_chunk
);
813 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
814 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
816 empty_chunk
.chunk_number
= 7;
817 empty_chunk
.is_add
= false;
818 chunks
.push_back(empty_chunk
);
819 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
820 database_
->UpdateFinished(true);
822 GetListsInfo(&lists
);
823 EXPECT_EQ(lists
[0].adds
, "1,10,19");
824 EXPECT_EQ(lists
[0].subs
, "7");
826 // Add an empty chunk along with a couple that contain data. This should
827 // result in the chunk range being reduced in size.
828 empty_chunk
.hosts
.clear();
829 InsertAddChunkHostPrefixUrl(&empty_chunk
, 20, "www.notempy.com/",
830 "www.notempty.com/full1.html");
832 chunks
.push_back(empty_chunk
);
834 empty_chunk
.chunk_number
= 21;
835 empty_chunk
.is_add
= true;
836 empty_chunk
.hosts
.clear();
837 chunks
.push_back(empty_chunk
);
839 empty_chunk
.hosts
.clear();
840 InsertAddChunkHostPrefixUrl(&empty_chunk
, 22, "www.notempy.com/",
841 "www.notempty.com/full2.html");
842 chunks
.push_back(empty_chunk
);
844 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
845 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
846 database_
->UpdateFinished(true);
848 const Time now
= Time::Now();
849 std::vector
<SBFullHashResult
> cached_hashes
;
850 std::vector
<SBPrefix
> prefix_hits
;
851 EXPECT_TRUE(database_
->ContainsBrowseUrl(
852 GURL("http://www.notempty.com/full1.html"),
853 &prefix_hits
, &cached_hashes
, now
));
854 EXPECT_TRUE(database_
->ContainsBrowseUrl(
855 GURL("http://www.notempty.com/full2.html"),
856 &prefix_hits
, &cached_hashes
, now
));
858 GetListsInfo(&lists
);
859 EXPECT_EQ(lists
[0].adds
, "1,10,19-22");
860 EXPECT_EQ(lists
[0].subs
, "7");
862 // Handle AddDel and SubDel commands for empty chunks.
863 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
864 AddDelChunk(safe_browsing_util::kMalwareList
, 21);
865 database_
->UpdateFinished(true);
867 GetListsInfo(&lists
);
868 EXPECT_EQ(lists
[0].adds
, "1,10,19-20,22");
869 EXPECT_EQ(lists
[0].subs
, "7");
871 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
872 SubDelChunk(safe_browsing_util::kMalwareList
, 7);
873 database_
->UpdateFinished(true);
875 GetListsInfo(&lists
);
876 EXPECT_EQ(lists
[0].adds
, "1,10,19-20,22");
877 EXPECT_EQ(lists
[0].subs
, "");
880 // Utility function for setting up the database for the caching test.
881 void SafeBrowsingDatabaseTest::PopulateDatabaseForCacheTest() {
884 // Add a simple chunk with one hostkey and cache it.
885 InsertAddChunkHost2PrefixUrls(&chunk
, 1, "www.evil.com/",
886 "www.evil.com/phishing.html",
887 "www.evil.com/malware.html");
888 chunks
.push_back(chunk
);
890 std::vector
<SBListChunkRanges
> lists
;
891 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
892 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
893 database_
->UpdateFinished(true);
895 // Add the GetHash results to the cache.
896 SBFullHashResult full_hash
;
897 full_hash
.hash
= SBFullHashForString("www.evil.com/phishing.html");
898 full_hash
.list_id
= safe_browsing_util::MALWARE
;
900 std::vector
<SBFullHashResult
> results
;
901 results
.push_back(full_hash
);
903 full_hash
.hash
= SBFullHashForString("www.evil.com/malware.html");
904 results
.push_back(full_hash
);
906 std::vector
<SBPrefix
> prefixes
;
907 database_
->CacheHashResults(prefixes
, results
);
910 TEST_F(SafeBrowsingDatabaseTest
, HashCaching
) {
911 PopulateDatabaseForCacheTest();
913 // We should have both full hashes in the cache.
914 EXPECT_EQ(2U, database_
->cached_browse_hashes_
.size());
916 // Test the cache lookup for the first prefix.
917 std::vector
<SBPrefix
> prefixes
;
918 std::vector
<SBFullHashResult
> cached_hashes
;
919 database_
->ContainsBrowseUrl(
920 GURL("http://www.evil.com/phishing.html"),
921 &prefixes
, &cached_hashes
, Time::Now());
922 ASSERT_EQ(1U, cached_hashes
.size());
924 SBFullHashEqual(cached_hashes
[0].hash
,
925 SBFullHashForString("www.evil.com/phishing.html")));
928 cached_hashes
.clear();
930 // Test the cache lookup for the second prefix.
931 database_
->ContainsBrowseUrl(
932 GURL("http://www.evil.com/malware.html"),
933 &prefixes
, &cached_hashes
, Time::Now());
934 ASSERT_EQ(1U, cached_hashes
.size());
936 SBFullHashEqual(cached_hashes
[0].hash
,
937 SBFullHashForString("www.evil.com/malware.html")));
940 cached_hashes
.clear();
942 // Test removing a prefix via a sub chunk.
945 InsertSubChunkHostPrefixUrl(&chunk
, 2, 1, "www.evil.com/",
946 "www.evil.com/phishing.html");
947 chunks
.push_back(chunk
);
949 std::vector
<SBListChunkRanges
> lists
;
950 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
951 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
952 database_
->UpdateFinished(true);
954 // This prefix should still be there, but the fullhash is gone.
955 EXPECT_TRUE(database_
->ContainsBrowseUrl(
956 GURL("http://www.evil.com/malware.html"),
957 &prefixes
, &cached_hashes
, Time::Now()));
958 ASSERT_EQ(1U, prefixes
.size());
959 EXPECT_EQ(SBPrefixForString("www.evil.com/malware.html"), prefixes
[0]);
960 EXPECT_TRUE(cached_hashes
.empty());
962 cached_hashes
.clear();
964 // This prefix should be gone.
965 database_
->ContainsBrowseUrl(
966 GURL("http://www.evil.com/phishing.html"),
967 &prefixes
, &cached_hashes
, Time::Now());
968 EXPECT_TRUE(cached_hashes
.empty());
971 cached_hashes
.clear();
973 // Test that an AddDel for the original chunk removes the last cached entry.
974 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
975 AddDelChunk(safe_browsing_util::kMalwareList
, 1);
976 database_
->UpdateFinished(true);
977 database_
->ContainsBrowseUrl(
978 GURL("http://www.evil.com/malware.html"),
979 &prefixes
, &cached_hashes
, Time::Now());
980 EXPECT_TRUE(cached_hashes
.empty());
981 EXPECT_TRUE(database_
->cached_browse_hashes_
.empty());
984 cached_hashes
.clear();
986 // Test that the cache won't return expired values. First we have to adjust
987 // the cached entries' received time to make them older, since the database
988 // cache insert uses Time::Now(). First, store some entries.
989 PopulateDatabaseForCacheTest();
991 std::vector
<SBFullHashCached
>* hash_cache
= &database_
->cached_browse_hashes_
;
992 EXPECT_EQ(2U, hash_cache
->size());
994 // Now adjust one of the entries times to be in the past.
995 base::Time expired
= base::Time::Now() - base::TimeDelta::FromMinutes(60);
996 const SBPrefix key
= SBPrefixForString("www.evil.com/malware.html");
997 std::vector
<SBFullHashCached
>::iterator iter
;
998 for (iter
= hash_cache
->begin(); iter
!= hash_cache
->end(); ++iter
) {
999 if (iter
->hash
.prefix
== key
) {
1000 iter
->received
= static_cast<int32
>(expired
.ToTimeT());
1004 EXPECT_TRUE(iter
!= hash_cache
->end());
1006 database_
->ContainsBrowseUrl(
1007 GURL("http://www.evil.com/malware.html"),
1008 &prefixes
, &cached_hashes
, expired
);
1009 EXPECT_TRUE(cached_hashes
.empty());
1011 // This entry should still exist.
1012 database_
->ContainsBrowseUrl(
1013 GURL("http://www.evil.com/phishing.html"),
1014 &prefixes
, &cached_hashes
, expired
);
1015 EXPECT_EQ(1U, cached_hashes
.size());
1017 // Testing prefix miss caching. First, we clear out the existing database,
1018 // Since PopulateDatabaseForCacheTest() doesn't handle adding duplicate
1020 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
1021 AddDelChunk(safe_browsing_util::kMalwareList
, 1);
1022 database_
->UpdateFinished(true);
1024 std::vector
<SBPrefix
> prefix_misses
;
1025 std::vector
<SBFullHashResult
> empty_full_hash
;
1026 prefix_misses
.push_back(SBPrefixForString("http://www.bad.com/malware.html"));
1027 prefix_misses
.push_back(
1028 SBPrefixForString("http://www.bad.com/phishing.html"));
1029 database_
->CacheHashResults(prefix_misses
, empty_full_hash
);
1031 // Prefixes with no full results are misses.
1032 EXPECT_EQ(2U, database_
->prefix_miss_cache_
.size());
1034 // Update the database.
1035 PopulateDatabaseForCacheTest();
1037 // Prefix miss cache should be cleared.
1038 EXPECT_TRUE(database_
->prefix_miss_cache_
.empty());
1040 // Cache a GetHash miss for a particular prefix, and even though the prefix is
1041 // in the database, it is flagged as a miss so looking up the associated URL
1042 // will not succeed.
1044 cached_hashes
.clear();
1045 prefix_misses
.clear();
1046 empty_full_hash
.clear();
1047 prefix_misses
.push_back(SBPrefixForString("www.evil.com/phishing.html"));
1048 database_
->CacheHashResults(prefix_misses
, empty_full_hash
);
1049 EXPECT_FALSE(database_
->ContainsBrowseUrl(
1050 GURL("http://www.evil.com/phishing.html"),
1051 &prefixes
, &cached_hashes
, Time::Now()));
1054 cached_hashes
.clear();
1056 // Test receiving a full add chunk.
1057 chunk
.hosts
.clear();
1058 InsertAddChunkHost2FullHashes(&chunk
, 20, "www.fullevil.com/",
1059 "www.fullevil.com/bad1.html",
1060 "www.fullevil.com/bad2.html");
1062 chunks
.push_back(chunk
);
1063 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
1064 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
1065 database_
->UpdateFinished(true);
1067 EXPECT_TRUE(database_
->ContainsBrowseUrl(
1068 GURL("http://www.fullevil.com/bad1.html"),
1069 &prefixes
, &cached_hashes
, Time::Now()));
1070 EXPECT_TRUE(cached_hashes
.empty());
1071 ASSERT_EQ(1U, prefixes
.size());
1072 EXPECT_EQ(SBPrefixForString("www.fullevil.com/bad1.html"), prefixes
[0]);
1074 cached_hashes
.clear();
1076 EXPECT_TRUE(database_
->ContainsBrowseUrl(
1077 GURL("http://www.fullevil.com/bad2.html"),
1078 &prefixes
, &cached_hashes
, Time::Now()));
1079 EXPECT_TRUE(cached_hashes
.empty());
1080 ASSERT_EQ(1U, prefixes
.size());
1081 EXPECT_EQ(SBPrefixForString("www.fullevil.com/bad2.html"), prefixes
[0]);
1083 cached_hashes
.clear();
1085 // Test receiving a full sub chunk, which will remove one of the full adds.
1086 chunk
.hosts
.clear();
1087 InsertSubChunkHostFullHash(&chunk
, 200, 20,
1088 "www.fullevil.com/",
1089 "www.fullevil.com/bad1.html");
1091 chunks
.push_back(chunk
);
1092 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
1093 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
1094 database_
->UpdateFinished(true);
1096 EXPECT_FALSE(database_
->ContainsBrowseUrl(
1097 GURL("http://www.fullevil.com/bad1.html"),
1098 &prefixes
, &cached_hashes
, Time::Now()));
1099 EXPECT_TRUE(cached_hashes
.empty());
1101 // There should be one remaining full add.
1102 EXPECT_TRUE(database_
->ContainsBrowseUrl(
1103 GURL("http://www.fullevil.com/bad2.html"),
1104 &prefixes
, &cached_hashes
, Time::Now()));
1105 EXPECT_TRUE(cached_hashes
.empty());
1106 ASSERT_EQ(1U, prefixes
.size());
1107 EXPECT_EQ(SBPrefixForString("www.fullevil.com/bad2.html"), prefixes
[0]);
1109 cached_hashes
.clear();
1111 // Now test an AddDel for the remaining full add.
1112 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
1113 AddDelChunk(safe_browsing_util::kMalwareList
, 20);
1114 database_
->UpdateFinished(true);
1116 EXPECT_FALSE(database_
->ContainsBrowseUrl(
1117 GURL("http://www.fullevil.com/bad1.html"),
1118 &prefixes
, &cached_hashes
, Time::Now()));
1119 EXPECT_FALSE(database_
->ContainsBrowseUrl(
1120 GURL("http://www.fullevil.com/bad2.html"),
1121 &prefixes
, &cached_hashes
, Time::Now()));
1123 // Add a fullhash which has a prefix collision for a known url.
1124 static const char kExampleFine
[] = "www.example.com/fine.html";
1125 static const char kExampleCollision
[] =
1126 "www.example.com/3123364814/malware.htm";
1127 ASSERT_EQ(SBPrefixForString(kExampleFine
),
1128 SBPrefixForString(kExampleCollision
));
1129 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
1133 InsertAddChunkHostPrefixUrl(&chunk
, 21, "www.example.com/",
1135 chunks
.push_back(chunk
);
1136 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
1138 database_
->UpdateFinished(true);
1140 // Cache gethash response for |kExampleCollision|.
1142 SBFullHashResult result
;
1143 result
.hash
= SBFullHashForString(kExampleCollision
);
1144 result
.list_id
= safe_browsing_util::MALWARE
;
1145 database_
->CacheHashResults(std::vector
<SBPrefix
>(1, result
.hash
.prefix
),
1146 std::vector
<SBFullHashResult
>(1, result
));
1149 // Expect a prefix hit due to the collision between |kExampleFine| and
1150 // |kExampleCollision|, with the gethash showing only |kExampleCollision|.
1151 EXPECT_TRUE(database_
->ContainsBrowseUrl(
1152 GURL(std::string("http://") + kExampleFine
),
1153 &prefixes
, &cached_hashes
, Time::Now()));
1154 ASSERT_EQ(1U, prefixes
.size());
1155 EXPECT_EQ(SBPrefixForString(kExampleFine
), prefixes
[0]);
1156 ASSERT_EQ(1U, cached_hashes
.size());
1157 EXPECT_TRUE(SBFullHashEqual(cached_hashes
[0].hash
,
1158 SBFullHashForString(kExampleCollision
)));
1161 // Test that corrupt databases are appropriately handled, even if the
1162 // corruption is detected in the midst of the update.
1163 // TODO(shess): Disabled until ScopedLogMessageIgnorer resolved.
1164 // http://crbug.com/56448
1165 TEST_F(SafeBrowsingDatabaseTest
, DISABLED_FileCorruptionHandling
) {
1166 // Re-create the database in a captive message loop so that we can
1167 // influence task-posting. Database specifically needs to the
1170 base::MessageLoop loop
;
1171 SafeBrowsingStoreFile
* store
= new SafeBrowsingStoreFile();
1172 database_
.reset(new SafeBrowsingDatabaseNew(store
, NULL
, NULL
, NULL
, NULL
,
1174 database_
->Init(database_filename_
);
1176 // This will cause an empty database to be created.
1177 std::vector
<SBListChunkRanges
> lists
;
1178 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
1179 database_
->UpdateFinished(true);
1181 // Create a sub chunk to insert.
1185 host
.host
= SBPrefixForString("www.subbed.com/");
1186 host
.entry
= SBEntry::Create(SBEntry::SUB_PREFIX
, 1);
1187 host
.entry
->set_chunk_id(7);
1188 host
.entry
->SetChunkIdAtPrefix(0, 19);
1189 host
.entry
->SetPrefixAt(0, SBPrefixForString("www.subbed.com/notevil1.html"));
1190 chunk
.chunk_number
= 7;
1191 chunk
.is_add
= false;
1192 chunk
.hosts
.clear();
1193 chunk
.hosts
.push_back(host
);
1195 chunks
.push_back(chunk
);
1197 // Corrupt the file by corrupting the checksum, which is not checked
1198 // until the entire table is read in |UpdateFinished()|.
1199 FILE* fp
= base::OpenFile(database_filename_
, "r+");
1201 ASSERT_NE(-1, fseek(fp
, -8, SEEK_END
));
1202 for (size_t i
= 0; i
< 8; ++i
) {
1208 // The following code will cause DCHECKs, so suppress the crashes.
1209 ScopedLogMessageIgnorer ignorer
;
1211 // Start an update. The insert will fail due to corruption.
1212 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
1213 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
1214 database_
->UpdateFinished(true);
1216 // Database file still exists until the corruption handler has run.
1217 EXPECT_TRUE(base::PathExists(database_filename_
));
1219 // Flush through the corruption-handler task.
1220 VLOG(1) << "Expect failed check on: SafeBrowsing database reset";
1221 base::MessageLoop::current()->RunUntilIdle();
1224 // Database file should not exist.
1225 EXPECT_FALSE(base::PathExists(database_filename_
));
1227 // Run the update again successfully.
1228 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
1229 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
1230 database_
->UpdateFinished(true);
1231 EXPECT_TRUE(base::PathExists(database_filename_
));
1236 // Checks database reading and writing.
1237 TEST_F(SafeBrowsingDatabaseTest
, ContainsDownloadUrl
) {
1239 base::MessageLoop loop
;
1240 SafeBrowsingStoreFile
* browse_store
= new SafeBrowsingStoreFile();
1241 SafeBrowsingStoreFile
* download_store
= new SafeBrowsingStoreFile();
1242 SafeBrowsingStoreFile
* csd_whitelist_store
= new SafeBrowsingStoreFile();
1243 database_
.reset(new SafeBrowsingDatabaseNew(browse_store
,
1245 csd_whitelist_store
,
1250 database_
->Init(database_filename_
);
1252 const char kEvil1Host
[] = "www.evil1.com/";
1253 const char kEvil1Url1
[] = "www.evil1.com/download1/";
1254 const char kEvil1Url2
[] = "www.evil1.com/download2.html";
1258 // Add a simple chunk with one hostkey for download url list.
1259 InsertAddChunkHost2PrefixUrls(&chunk
, 1, kEvil1Host
,
1260 kEvil1Url1
, kEvil1Url2
);
1261 chunks
.push_back(chunk
);
1262 std::vector
<SBListChunkRanges
> lists
;
1263 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
1264 database_
->InsertChunks(safe_browsing_util::kBinUrlList
, chunks
);
1265 database_
->UpdateFinished(true);
1267 std::vector
<SBPrefix
> prefix_hits
;
1268 std::vector
<GURL
> urls(1);
1270 urls
[0] = GURL(std::string("http://") + kEvil1Url1
);
1271 EXPECT_TRUE(database_
->ContainsDownloadUrl(urls
, &prefix_hits
));
1272 ASSERT_EQ(prefix_hits
.size(), 1U);
1273 EXPECT_EQ(prefix_hits
[0], SBPrefixForString(kEvil1Url1
));
1275 urls
[0] = GURL(std::string("http://") + kEvil1Url2
);
1276 EXPECT_TRUE(database_
->ContainsDownloadUrl(urls
, &prefix_hits
));
1277 ASSERT_EQ(prefix_hits
.size(), 1U);
1278 EXPECT_EQ(prefix_hits
[0], SBPrefixForString(kEvil1Url2
));
1280 urls
[0] = GURL(std::string("https://") + kEvil1Url2
);
1281 EXPECT_TRUE(database_
->ContainsDownloadUrl(urls
, &prefix_hits
));
1282 ASSERT_EQ(prefix_hits
.size(), 1U);
1283 EXPECT_EQ(prefix_hits
[0], SBPrefixForString(kEvil1Url2
));
1285 urls
[0] = GURL(std::string("ftp://") + kEvil1Url2
);
1286 EXPECT_TRUE(database_
->ContainsDownloadUrl(urls
, &prefix_hits
));
1287 ASSERT_EQ(prefix_hits
.size(), 1U);
1288 EXPECT_EQ(prefix_hits
[0], SBPrefixForString(kEvil1Url2
));
1290 urls
[0] = GURL("http://www.randomevil.com");
1291 EXPECT_FALSE(database_
->ContainsDownloadUrl(urls
, &prefix_hits
));
1293 // Should match with query args stripped.
1294 urls
[0] = GURL(std::string("http://") + kEvil1Url2
+ "?blah");
1295 EXPECT_TRUE(database_
->ContainsDownloadUrl(urls
, &prefix_hits
));
1296 ASSERT_EQ(prefix_hits
.size(), 1U);
1297 EXPECT_EQ(prefix_hits
[0], SBPrefixForString(kEvil1Url2
));
1299 // Should match with extra path stuff and query args stripped.
1300 urls
[0] = GURL(std::string("http://") + kEvil1Url1
+ "foo/bar?blah");
1301 EXPECT_TRUE(database_
->ContainsDownloadUrl(urls
, &prefix_hits
));
1302 ASSERT_EQ(prefix_hits
.size(), 1U);
1303 EXPECT_EQ(prefix_hits
[0], SBPrefixForString(kEvil1Url1
));
1305 // First hit in redirect chain is malware.
1307 urls
.push_back(GURL(std::string("http://") + kEvil1Url1
));
1308 urls
.push_back(GURL("http://www.randomevil.com"));
1309 EXPECT_TRUE(database_
->ContainsDownloadUrl(urls
, &prefix_hits
));
1310 ASSERT_EQ(prefix_hits
.size(), 1U);
1311 EXPECT_EQ(prefix_hits
[0], SBPrefixForString(kEvil1Url1
));
1313 // Middle hit in redirect chain is malware.
1315 urls
.push_back(GURL("http://www.randomevil.com"));
1316 urls
.push_back(GURL(std::string("http://") + kEvil1Url1
));
1317 urls
.push_back(GURL("http://www.randomevil2.com"));
1318 EXPECT_TRUE(database_
->ContainsDownloadUrl(urls
, &prefix_hits
));
1319 ASSERT_EQ(prefix_hits
.size(), 1U);
1320 EXPECT_EQ(prefix_hits
[0], SBPrefixForString(kEvil1Url1
));
1322 // Final hit in redirect chain is malware.
1324 urls
.push_back(GURL("http://www.randomevil.com"));
1325 urls
.push_back(GURL(std::string("http://") + kEvil1Url1
));
1326 EXPECT_TRUE(database_
->ContainsDownloadUrl(urls
, &prefix_hits
));
1327 ASSERT_EQ(prefix_hits
.size(), 1U);
1328 EXPECT_EQ(prefix_hits
[0], SBPrefixForString(kEvil1Url1
));
1330 // Multiple hits in redirect chain are in malware list.
1332 urls
.push_back(GURL(std::string("http://") + kEvil1Url1
));
1333 urls
.push_back(GURL(std::string("https://") + kEvil1Url2
));
1334 EXPECT_TRUE(database_
->ContainsDownloadUrl(urls
, &prefix_hits
));
1335 ASSERT_EQ(prefix_hits
.size(), 2U);
1336 EXPECT_EQ(prefix_hits
[0], SBPrefixForString(kEvil1Url1
));
1337 EXPECT_EQ(prefix_hits
[1], SBPrefixForString(kEvil1Url2
));
1341 // Checks that the whitelists are handled properly.
1342 TEST_F(SafeBrowsingDatabaseTest
, Whitelists
) {
1344 // We expect all calls to ContainsCsdWhitelistedUrl in particular to be made
1345 // from the IO thread. In general the whitelist lookups are thread-safe.
1346 content::TestBrowserThreadBundle thread_bundle_
;
1348 // If the whitelist is disabled everything should match the whitelist.
1349 database_
.reset(new SafeBrowsingDatabaseNew(new SafeBrowsingStoreFile(),
1350 NULL
, NULL
, NULL
, NULL
, NULL
,
1352 database_
->Init(database_filename_
);
1353 EXPECT_TRUE(database_
->ContainsDownloadWhitelistedUrl(
1354 GURL(std::string("http://www.phishing.com/"))));
1355 EXPECT_TRUE(database_
->ContainsDownloadWhitelistedUrl(
1356 GURL(std::string("http://www.phishing.com/"))));
1357 EXPECT_TRUE(database_
->ContainsDownloadWhitelistedString("asdf"));
1359 SafeBrowsingStoreFile
* browse_store
= new SafeBrowsingStoreFile();
1360 SafeBrowsingStoreFile
* csd_whitelist_store
= new SafeBrowsingStoreFile();
1361 SafeBrowsingStoreFile
* download_whitelist_store
= new SafeBrowsingStoreFile();
1362 SafeBrowsingStoreFile
* extension_blacklist_store
=
1363 new SafeBrowsingStoreFile();
1364 database_
.reset(new SafeBrowsingDatabaseNew(browse_store
, NULL
,
1365 csd_whitelist_store
,
1366 download_whitelist_store
,
1367 extension_blacklist_store
,
1369 database_
->Init(database_filename_
);
1371 const char kGood1Host
[] = "www.good1.com/";
1372 const char kGood1Url1
[] = "www.good1.com/a/b.html";
1373 const char kGood1Url2
[] = "www.good1.com/b/";
1375 const char kGood2Host
[] = "www.good2.com/";
1376 const char kGood2Url1
[] = "www.good2.com/c"; // Should match '/c/bla'.
1378 // good3.com/a/b/c/d/e/f/g/ should match because it's a whitelist.
1379 const char kGood3Host
[] = "good3.com/";
1380 const char kGood3Url1
[] = "good3.com/";
1382 const char kGoodString
[] = "good_string";
1384 SBChunkList download_chunks
, csd_chunks
;
1386 // Add two simple chunks to the csd whitelist.
1387 InsertAddChunkHost2FullHashes(&chunk
, 1, kGood1Host
,
1388 kGood1Url1
, kGood1Url2
);
1389 csd_chunks
.push_back(chunk
);
1391 chunk
.hosts
.clear();
1392 InsertAddChunkHostFullHashes(&chunk
, 2, kGood2Host
, kGood2Url1
);
1393 csd_chunks
.push_back(chunk
);
1395 chunk
.hosts
.clear();
1396 InsertAddChunkHostFullHashes(&chunk
, 2, kGood2Host
, kGood2Url1
);
1397 download_chunks
.push_back(chunk
);
1399 chunk
.hosts
.clear();
1400 InsertAddChunkHostFullHashes(&chunk
, 3, kGoodString
, kGoodString
);
1401 download_chunks
.push_back(chunk
);
1403 chunk
.hosts
.clear();
1404 InsertAddChunkHostFullHashes(&chunk
, 4, kGood3Host
, kGood3Url1
);
1405 download_chunks
.push_back(chunk
);
1407 std::vector
<SBListChunkRanges
> lists
;
1408 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
1409 database_
->InsertChunks(safe_browsing_util::kCsdWhiteList
,
1411 database_
->InsertChunks(safe_browsing_util::kDownloadWhiteList
,
1413 database_
->UpdateFinished(true);
1415 EXPECT_FALSE(database_
->ContainsCsdWhitelistedUrl(
1416 GURL(std::string("http://") + kGood1Host
)));
1418 EXPECT_TRUE(database_
->ContainsCsdWhitelistedUrl(
1419 GURL(std::string("http://") + kGood1Url1
)));
1420 EXPECT_TRUE(database_
->ContainsCsdWhitelistedUrl(
1421 GURL(std::string("http://") + kGood1Url1
+ "?a=b")));
1423 EXPECT_TRUE(database_
->ContainsCsdWhitelistedUrl(
1424 GURL(std::string("http://") + kGood1Url2
)));
1425 EXPECT_TRUE(database_
->ContainsCsdWhitelistedUrl(
1426 GURL(std::string("http://") + kGood1Url2
+ "/c.html")));
1428 EXPECT_TRUE(database_
->ContainsCsdWhitelistedUrl(
1429 GURL(std::string("https://") + kGood1Url2
+ "/c.html")));
1431 EXPECT_TRUE(database_
->ContainsCsdWhitelistedUrl(
1432 GURL(std::string("http://") + kGood2Url1
+ "/c")));
1433 EXPECT_TRUE(database_
->ContainsCsdWhitelistedUrl(
1434 GURL(std::string("http://") + kGood2Url1
+ "/c?bla")));
1435 EXPECT_TRUE(database_
->ContainsCsdWhitelistedUrl(
1436 GURL(std::string("http://") + kGood2Url1
+ "/c/bla")));
1438 EXPECT_FALSE(database_
->ContainsCsdWhitelistedUrl(
1439 GURL(std::string("http://www.google.com/"))));
1441 EXPECT_TRUE(database_
->ContainsDownloadWhitelistedUrl(
1442 GURL(std::string("http://") + kGood2Url1
+ "/c")));
1443 EXPECT_TRUE(database_
->ContainsDownloadWhitelistedUrl(
1444 GURL(std::string("http://") + kGood2Url1
+ "/c?bla")));
1445 EXPECT_TRUE(database_
->ContainsDownloadWhitelistedUrl(
1446 GURL(std::string("http://") + kGood2Url1
+ "/c/bla")));
1448 EXPECT_TRUE(database_
->ContainsDownloadWhitelistedUrl(
1449 GURL(std::string("http://good3.com/a/b/c/d/e/f/g/"))));
1450 EXPECT_TRUE(database_
->ContainsDownloadWhitelistedUrl(
1451 GURL(std::string("http://a.b.good3.com/"))));
1453 EXPECT_FALSE(database_
->ContainsDownloadWhitelistedString("asdf"));
1454 EXPECT_TRUE(database_
->ContainsDownloadWhitelistedString(kGoodString
));
1456 EXPECT_FALSE(database_
->ContainsDownloadWhitelistedUrl(
1457 GURL(std::string("http://www.google.com/"))));
1459 // Test only add the malware IP killswitch
1461 chunk
.hosts
.clear();
1462 InsertAddChunkHostFullHashes(
1463 &chunk
, 15, "sb-ssl.google.com/",
1464 "sb-ssl.google.com/safebrowsing/csd/killswitch_malware");
1465 csd_chunks
.push_back(chunk
);
1466 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
1467 database_
->InsertChunks(safe_browsing_util::kCsdWhiteList
, csd_chunks
);
1468 database_
->UpdateFinished(true);
1470 EXPECT_TRUE(database_
->IsMalwareIPMatchKillSwitchOn());
1472 // Test that the kill-switch works as intended.
1474 download_chunks
.clear();
1476 chunk
.hosts
.clear();
1477 InsertAddChunkHostFullHashes(&chunk
, 5, "sb-ssl.google.com/",
1478 "sb-ssl.google.com/safebrowsing/csd/killswitch");
1479 csd_chunks
.push_back(chunk
);
1480 chunk
.hosts
.clear();
1481 InsertAddChunkHostFullHashes(&chunk
, 5, "sb-ssl.google.com/",
1482 "sb-ssl.google.com/safebrowsing/csd/killswitch");
1483 download_chunks
.push_back(chunk
);
1485 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
1486 database_
->InsertChunks(safe_browsing_util::kCsdWhiteList
, csd_chunks
);
1487 database_
->InsertChunks(safe_browsing_util::kDownloadWhiteList
,
1489 database_
->UpdateFinished(true);
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 EXPECT_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_TRUE(database_
->ContainsCsdWhitelistedUrl(
1539 GURL(std::string("https://") + kGood1Url2
+ "/c.html")));
1540 EXPECT_TRUE(database_
->ContainsCsdWhitelistedUrl(
1541 GURL(std::string("https://") + kGood2Url1
+ "/c/bla")));
1542 EXPECT_FALSE(database_
->ContainsCsdWhitelistedUrl(
1543 GURL(std::string("http://www.google.com/"))));
1544 EXPECT_FALSE(database_
->ContainsCsdWhitelistedUrl(
1545 GURL(std::string("http://www.phishing_url.com/"))));
1547 EXPECT_TRUE(database_
->ContainsDownloadWhitelistedUrl(
1548 GURL(std::string("https://") + kGood2Url1
+ "/c/bla")));
1549 EXPECT_TRUE(database_
->ContainsDownloadWhitelistedUrl(
1550 GURL(std::string("https://good3.com/"))));
1551 EXPECT_TRUE(database_
->ContainsDownloadWhitelistedString(kGoodString
));
1552 EXPECT_FALSE(database_
->ContainsDownloadWhitelistedUrl(
1553 GURL(std::string("http://www.google.com/"))));
1554 EXPECT_FALSE(database_
->ContainsDownloadWhitelistedUrl(
1555 GURL(std::string("http://www.phishing_url.com/"))));
1556 EXPECT_FALSE(database_
->ContainsDownloadWhitelistedString("asdf"));
1561 // Test to make sure we could insert chunk list that
1562 // contains entries for the same host.
1563 TEST_F(SafeBrowsingDatabaseTest
, SameHostEntriesOkay
) {
1566 // Add a malware add chunk with two entries of the same host.
1567 InsertAddChunkHostPrefixUrl(&chunk
, 1, "www.evil.com/",
1568 "www.evil.com/malware1.html");
1569 InsertAddChunkHostPrefixUrl(&chunk
, 1, "www.evil.com/",
1570 "www.evil.com/malware2.html");
1572 chunks
.push_back(chunk
);
1574 // Insert the testing chunks into database.
1575 std::vector
<SBListChunkRanges
> lists
;
1576 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
1577 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
1578 database_
->UpdateFinished(true);
1580 GetListsInfo(&lists
);
1581 EXPECT_EQ(std::string(safe_browsing_util::kMalwareList
), lists
[0].name
);
1582 EXPECT_EQ("1", lists
[0].adds
);
1583 EXPECT_TRUE(lists
[0].subs
.empty());
1585 // Add a phishing add chunk with two entries of the same host.
1586 chunk
.hosts
.clear();
1587 InsertAddChunkHostPrefixUrl(&chunk
, 47, "www.evil.com/",
1588 "www.evil.com/phishing1.html");
1589 InsertAddChunkHostPrefixUrl(&chunk
, 47, "www.evil.com/",
1590 "www.evil.com/phishing2.html");
1592 chunks
.push_back(chunk
);
1594 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
1595 database_
->InsertChunks(safe_browsing_util::kPhishingList
, chunks
);
1596 database_
->UpdateFinished(true);
1598 GetListsInfo(&lists
);
1599 EXPECT_EQ(std::string(safe_browsing_util::kMalwareList
), lists
[0].name
);
1600 EXPECT_EQ("1", lists
[0].adds
);
1601 EXPECT_EQ(std::string(safe_browsing_util::kPhishingList
), lists
[1].name
);
1602 EXPECT_EQ("47", lists
[1].adds
);
1604 const Time now
= Time::Now();
1605 std::vector
<SBPrefix
> prefixes
;
1606 std::vector
<SBFullHashResult
> cached_hashes
;
1607 std::vector
<SBPrefix
> prefix_hits
;
1609 EXPECT_TRUE(database_
->ContainsBrowseUrl(
1610 GURL("http://www.evil.com/malware1.html"),
1611 &prefixes
, &cached_hashes
, now
));
1612 EXPECT_TRUE(database_
->ContainsBrowseUrl(
1613 GURL("http://www.evil.com/malware2.html"),
1614 &prefixes
, &cached_hashes
, now
));
1615 EXPECT_TRUE(database_
->ContainsBrowseUrl(
1616 GURL("http://www.evil.com/phishing1.html"),
1617 &prefixes
, &cached_hashes
, now
));
1618 EXPECT_TRUE(database_
->ContainsBrowseUrl(
1619 GURL("http://www.evil.com/phishing2.html"),
1620 &prefixes
, &cached_hashes
, now
));
1622 // Test removing a single prefix from the add chunk.
1623 // Remove the prefix that added first.
1624 chunk
.hosts
.clear();
1625 InsertSubChunkHostPrefixUrl(&chunk
, 4, 1, "www.evil.com/",
1626 "www.evil.com/malware1.html");
1628 chunks
.push_back(chunk
);
1629 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
1630 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
1631 database_
->UpdateFinished(true);
1633 // Remove the prefix that added last.
1634 chunk
.hosts
.clear();
1635 InsertSubChunkHostPrefixUrl(&chunk
, 5, 47, "www.evil.com/",
1636 "www.evil.com/phishing2.html");
1638 chunks
.push_back(chunk
);
1639 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
1640 database_
->InsertChunks(safe_browsing_util::kPhishingList
, chunks
);
1641 database_
->UpdateFinished(true);
1643 // Verify that the database contains urls expected.
1644 EXPECT_FALSE(database_
->ContainsBrowseUrl(
1645 GURL("http://www.evil.com/malware1.html"),
1646 &prefixes
, &cached_hashes
, now
));
1647 EXPECT_TRUE(database_
->ContainsBrowseUrl(
1648 GURL("http://www.evil.com/malware2.html"),
1649 &prefixes
, &cached_hashes
, now
));
1650 EXPECT_TRUE(database_
->ContainsBrowseUrl(
1651 GURL("http://www.evil.com/phishing1.html"),
1652 &prefixes
, &cached_hashes
, now
));
1653 EXPECT_FALSE(database_
->ContainsBrowseUrl(
1654 GURL("http://www.evil.com/phishing2.html"),
1655 &prefixes
, &cached_hashes
, now
));
1658 // Test that an empty update doesn't actually update the database.
1659 // This isn't a functionality requirement, but it is a useful
1661 TEST_F(SafeBrowsingDatabaseTest
, EmptyUpdate
) {
1665 base::FilePath filename
= database_
->BrowseDBFilename(database_filename_
);
1667 // Prime the database.
1668 std::vector
<SBListChunkRanges
> lists
;
1669 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
1671 InsertAddChunkHostPrefixUrl(&chunk
, 1, "www.evil.com/",
1672 "www.evil.com/malware.html");
1674 chunks
.push_back(chunk
);
1675 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
1676 database_
->UpdateFinished(true);
1678 // Get an older time to reset the lastmod time for detecting whether
1679 // the file has been updated.
1680 base::File::Info before_info
, after_info
;
1681 ASSERT_TRUE(base::GetFileInfo(filename
, &before_info
));
1682 const base::Time old_last_modified
=
1683 before_info
.last_modified
- base::TimeDelta::FromSeconds(10);
1685 // Inserting another chunk updates the database file. The sleep is
1686 // needed because otherwise the entire test can finish w/in the
1687 // resolution of the lastmod time.
1688 ASSERT_TRUE(base::TouchFile(filename
, old_last_modified
, old_last_modified
));
1689 ASSERT_TRUE(base::GetFileInfo(filename
, &before_info
));
1690 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
1691 chunk
.hosts
.clear();
1692 InsertAddChunkHostPrefixUrl(&chunk
, 2, "www.foo.com/",
1693 "www.foo.com/malware.html");
1695 chunks
.push_back(chunk
);
1696 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
1697 database_
->UpdateFinished(true);
1698 ASSERT_TRUE(base::GetFileInfo(filename
, &after_info
));
1699 EXPECT_LT(before_info
.last_modified
, after_info
.last_modified
);
1701 // Deleting a chunk updates the database file.
1702 ASSERT_TRUE(base::TouchFile(filename
, old_last_modified
, old_last_modified
));
1703 ASSERT_TRUE(base::GetFileInfo(filename
, &before_info
));
1704 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
1705 AddDelChunk(safe_browsing_util::kMalwareList
, chunk
.chunk_number
);
1706 database_
->UpdateFinished(true);
1707 ASSERT_TRUE(base::GetFileInfo(filename
, &after_info
));
1708 EXPECT_LT(before_info
.last_modified
, after_info
.last_modified
);
1710 // Simply calling |UpdateStarted()| then |UpdateFinished()| does not
1711 // update the database file.
1712 ASSERT_TRUE(base::TouchFile(filename
, old_last_modified
, old_last_modified
));
1713 ASSERT_TRUE(base::GetFileInfo(filename
, &before_info
));
1714 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
1715 database_
->UpdateFinished(true);
1716 ASSERT_TRUE(base::GetFileInfo(filename
, &after_info
));
1717 EXPECT_EQ(before_info
.last_modified
, after_info
.last_modified
);
1720 // Test that a filter file is written out during update and read back
1722 TEST_F(SafeBrowsingDatabaseTest
, FilterFile
) {
1723 // Create a database with trivial example data and write it out.
1728 // Prime the database.
1729 std::vector
<SBListChunkRanges
> lists
;
1730 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
1732 InsertAddChunkHostPrefixUrl(&chunk
, 1, "www.evil.com/",
1733 "www.evil.com/malware.html");
1735 chunks
.push_back(chunk
);
1736 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
1737 database_
->UpdateFinished(true);
1740 // Find the malware url in the database, don't find a good url.
1741 const Time now
= Time::Now();
1742 std::vector
<SBFullHashResult
> cached_hashes
;
1743 std::vector
<SBPrefix
> prefix_hits
;
1744 EXPECT_TRUE(database_
->ContainsBrowseUrl(
1745 GURL("http://www.evil.com/malware.html"),
1746 &prefix_hits
, &cached_hashes
, now
));
1747 EXPECT_FALSE(database_
->ContainsBrowseUrl(
1748 GURL("http://www.good.com/goodware.html"),
1749 &prefix_hits
, &cached_hashes
, now
));
1751 base::FilePath filter_file
= database_
->PrefixSetForFilename(
1752 database_
->BrowseDBFilename(database_filename_
));
1754 // After re-creating the database, it should have a filter read from
1755 // a file, so it should find the same results.
1756 ASSERT_TRUE(base::PathExists(filter_file
));
1757 database_
.reset(new SafeBrowsingDatabaseNew
);
1758 database_
->Init(database_filename_
);
1759 EXPECT_TRUE(database_
->ContainsBrowseUrl(
1760 GURL("http://www.evil.com/malware.html"),
1761 &prefix_hits
, &cached_hashes
, now
));
1762 EXPECT_FALSE(database_
->ContainsBrowseUrl(
1763 GURL("http://www.good.com/goodware.html"),
1764 &prefix_hits
, &cached_hashes
, now
));
1766 // If there is no filter file, the database cannot find malware urls.
1767 base::DeleteFile(filter_file
, false);
1768 ASSERT_FALSE(base::PathExists(filter_file
));
1769 database_
.reset(new SafeBrowsingDatabaseNew
);
1770 database_
->Init(database_filename_
);
1771 EXPECT_FALSE(database_
->ContainsBrowseUrl(
1772 GURL("http://www.evil.com/malware.html"),
1773 &prefix_hits
, &cached_hashes
, now
));
1774 EXPECT_FALSE(database_
->ContainsBrowseUrl(
1775 GURL("http://www.good.com/goodware.html"),
1776 &prefix_hits
, &cached_hashes
, now
));
1779 TEST_F(SafeBrowsingDatabaseTest
, MalwareIpBlacklist
) {
1781 SafeBrowsingStoreFile
* browse_store
= new SafeBrowsingStoreFile();
1782 SafeBrowsingStoreFile
* ip_blacklist_store
= new SafeBrowsingStoreFile();
1783 database_
.reset(new SafeBrowsingDatabaseNew(browse_store
,
1789 ip_blacklist_store
));
1790 database_
->Init(database_filename_
);
1791 std::vector
<SBListChunkRanges
> lists
;
1792 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
1794 // IPv4 prefix match for ::ffff:192.168.1.0/120.
1797 InsertAddChunkFullHash(&chunk
, 1, "::ffff:192.168.1.0", 120);
1798 chunks
.push_back(chunk
);
1799 database_
->InsertChunks(safe_browsing_util::kIPBlacklist
, chunks
);
1801 // IPv4 exact match for ::ffff:192.1.1.1.
1803 chunk
.hosts
.clear();
1804 InsertAddChunkFullHash(&chunk
, 2, "::ffff:192.1.1.1", 128);
1805 chunks
.push_back(chunk
);
1806 database_
->InsertChunks(safe_browsing_util::kIPBlacklist
, chunks
);
1808 // IPv6 exact match for: fe80::31a:a0ff:fe10:786e/128.
1810 chunk
.hosts
.clear();
1811 InsertAddChunkFullHash(&chunk
, 3, "fe80::31a:a0ff:fe10:786e", 128);
1812 chunks
.push_back(chunk
);
1813 database_
->InsertChunks(safe_browsing_util::kIPBlacklist
, chunks
);
1815 // IPv6 prefix match for: 2620:0:1000:3103::/64.
1817 chunk
.hosts
.clear();
1818 InsertAddChunkFullHash(&chunk
, 4, "2620:0:1000:3103::", 64);
1819 chunks
.push_back(chunk
);
1820 database_
->InsertChunks(safe_browsing_util::kIPBlacklist
, chunks
);
1822 // IPv4 prefix match for ::ffff:192.1.122.0/119.
1824 chunk
.hosts
.clear();
1825 InsertAddChunkFullHash(&chunk
, 5, "::ffff:192.1.122.0", 119);
1826 chunks
.push_back(chunk
);
1827 database_
->InsertChunks(safe_browsing_util::kIPBlacklist
, chunks
);
1829 // IPv4 prefix match for ::ffff:192.1.128.0/113.
1831 chunk
.hosts
.clear();
1832 InsertAddChunkFullHash(&chunk
, 6, "::ffff:192.1.128.0", 113);
1833 chunks
.push_back(chunk
);
1834 database_
->InsertChunks(safe_browsing_util::kIPBlacklist
, chunks
);
1836 database_
->UpdateFinished(true);
1838 EXPECT_FALSE(database_
->ContainsMalwareIP("192.168.0.255"));
1839 EXPECT_TRUE(database_
->ContainsMalwareIP("192.168.1.0"));
1840 EXPECT_TRUE(database_
->ContainsMalwareIP("192.168.1.255"));
1841 EXPECT_TRUE(database_
->ContainsMalwareIP("192.168.1.10"));
1842 EXPECT_TRUE(database_
->ContainsMalwareIP("::ffff:192.168.1.2"));
1843 EXPECT_FALSE(database_
->ContainsMalwareIP("192.168.2.0"));
1845 EXPECT_FALSE(database_
->ContainsMalwareIP("192.1.1.0"));
1846 EXPECT_TRUE(database_
->ContainsMalwareIP("192.1.1.1"));
1847 EXPECT_FALSE(database_
->ContainsMalwareIP("192.1.1.2"));
1849 EXPECT_FALSE(database_
->ContainsMalwareIP(
1850 "2620:0:1000:3102:ffff:ffff:ffff:ffff"));
1851 EXPECT_TRUE(database_
->ContainsMalwareIP("2620:0:1000:3103::"));
1852 EXPECT_TRUE(database_
->ContainsMalwareIP(
1853 "2620:0:1000:3103:ffff:ffff:ffff:ffff"));
1854 EXPECT_FALSE(database_
->ContainsMalwareIP("2620:0:1000:3104::"));
1856 EXPECT_FALSE(database_
->ContainsMalwareIP("fe80::21a:a0ff:fe10:786d"));
1857 EXPECT_TRUE(database_
->ContainsMalwareIP("fe80::31a:a0ff:fe10:786e"));
1858 EXPECT_FALSE(database_
->ContainsMalwareIP("fe80::21a:a0ff:fe10:786f"));
1860 EXPECT_FALSE(database_
->ContainsMalwareIP("192.1.121.255"));
1861 EXPECT_TRUE(database_
->ContainsMalwareIP("192.1.122.0"));
1862 EXPECT_TRUE(database_
->ContainsMalwareIP("::ffff:192.1.122.1"));
1863 EXPECT_TRUE(database_
->ContainsMalwareIP("192.1.122.255"));
1864 EXPECT_TRUE(database_
->ContainsMalwareIP("192.1.123.0"));
1865 EXPECT_TRUE(database_
->ContainsMalwareIP("192.1.123.255"));
1866 EXPECT_FALSE(database_
->ContainsMalwareIP("192.1.124.0"));
1868 EXPECT_FALSE(database_
->ContainsMalwareIP("192.1.127.255"));
1869 EXPECT_TRUE(database_
->ContainsMalwareIP("192.1.128.0"));
1870 EXPECT_TRUE(database_
->ContainsMalwareIP("::ffff:192.1.128.1"));
1871 EXPECT_TRUE(database_
->ContainsMalwareIP("192.1.128.255"));
1872 EXPECT_TRUE(database_
->ContainsMalwareIP("192.1.255.0"));
1873 EXPECT_TRUE(database_
->ContainsMalwareIP("192.1.255.255"));
1874 EXPECT_FALSE(database_
->ContainsMalwareIP("192.2.0.0"));
1877 TEST_F(SafeBrowsingDatabaseTest
, ContainsBrowseURL
) {
1878 std::vector
<SBListChunkRanges
> lists
;
1879 EXPECT_TRUE(database_
->UpdateStarted(&lists
));
1881 // Add a host-level hit.
1885 InsertAddChunkHostPrefix(&chunk
, 1, "www.evil.com/");
1886 chunks
.push_back(chunk
);
1887 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
1890 // Add a specific fullhash.
1891 static const char kWhateverMalware
[] = "www.whatever.com/malware.html";
1895 InsertAddChunkHostFullHashes(&chunk
, 2, "www.whatever.com/",
1897 chunks
.push_back(chunk
);
1898 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
1901 // Add a fullhash which has a prefix collision for a known url.
1902 static const char kExampleFine
[] = "www.example.com/fine.html";
1903 static const char kExampleCollision
[] =
1904 "www.example.com/3123364814/malware.htm";
1905 ASSERT_EQ(SBPrefixForString(kExampleFine
),
1906 SBPrefixForString(kExampleCollision
));
1910 InsertAddChunkHostFullHashes(&chunk
, 3, "www.example.com/",
1912 chunks
.push_back(chunk
);
1913 database_
->InsertChunks(safe_browsing_util::kMalwareList
, chunks
);
1916 database_
->UpdateFinished(true);
1918 const Time now
= Time::Now();
1919 std::vector
<SBFullHashResult
> cached_hashes
;
1920 std::vector
<SBPrefix
> prefix_hits
;
1922 // Anything will hit the host prefix.
1923 EXPECT_TRUE(database_
->ContainsBrowseUrl(
1924 GURL("http://www.evil.com/malware.html"),
1925 &prefix_hits
, &cached_hashes
, now
));
1926 ASSERT_EQ(1U, prefix_hits
.size());
1927 EXPECT_EQ(SBPrefixForString("www.evil.com/"), prefix_hits
[0]);
1928 EXPECT_TRUE(cached_hashes
.empty());
1930 // Hit the specific URL prefix.
1931 EXPECT_TRUE(database_
->ContainsBrowseUrl(
1932 GURL(std::string("http://") + kWhateverMalware
),
1933 &prefix_hits
, &cached_hashes
, now
));
1934 ASSERT_EQ(1U, prefix_hits
.size());
1935 EXPECT_EQ(SBPrefixForString(kWhateverMalware
), prefix_hits
[0]);
1936 EXPECT_TRUE(cached_hashes
.empty());
1938 // Other URLs at that host are fine.
1939 EXPECT_FALSE(database_
->ContainsBrowseUrl(
1940 GURL("http://www.whatever.com/fine.html"),
1941 &prefix_hits
, &cached_hashes
, now
));
1942 EXPECT_TRUE(prefix_hits
.empty());
1943 EXPECT_TRUE(cached_hashes
.empty());
1945 // Hit the specific URL full hash.
1946 EXPECT_TRUE(database_
->ContainsBrowseUrl(
1947 GURL(std::string("http://") + kExampleCollision
),
1948 &prefix_hits
, &cached_hashes
, now
));
1949 ASSERT_EQ(1U, prefix_hits
.size());
1950 EXPECT_EQ(SBPrefixForString(kExampleCollision
), prefix_hits
[0]);
1951 EXPECT_TRUE(cached_hashes
.empty());
1953 // This prefix collides, but no full hash match.
1954 EXPECT_FALSE(database_
->ContainsBrowseUrl(
1955 GURL(std::string("http://") + kExampleFine
),
1956 &prefix_hits
, &cached_hashes
, now
));