diff options
author | lzheng@chromium.org <lzheng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-12 19:24:21 +0000 |
---|---|---|
committer | lzheng@chromium.org <lzheng@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2011-01-12 19:24:21 +0000 |
commit | f5ce36af4ed345203bed9312bb2a2f16a900a6c9 (patch) | |
tree | 81bdf7ba1f3de41fb999fb315188b43ce6fbccd2 | |
parent | 9cb116d30b6d6a52f11270abf7cea80bfa7fc738 (diff) | |
download | chromium_src-f5ce36af4ed345203bed9312bb2a2f16a900a6c9.zip chromium_src-f5ce36af4ed345203bed9312bb2a2f16a900a6c9.tar.gz chromium_src-f5ce36af4ed345203bed9312bb2a2f16a900a6c9.tar.bz2 |
Parse binhash sent from safebrowsing server.
The binhash will be in this format for add-data ans sub-data:
ADD-DATA = (PREFIX)+
PREFIX = <HASHLEN unsigned bytes>
SUB-DATA = (ADDCHUNKNUM PREFIX)+
ADDCHUNKNUM = <4 byte unsigned integer in network byte order>
PREFIX = <HASHLEN unsigned bytes>
BUG=60822
TEST=safe_browsing_database_unittest.cc,protocol_parser_unittest.cc
Review URL: http://codereview.chromium.org/6025002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@71213 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | chrome/browser/safe_browsing/protocol_manager.cc | 2 | ||||
-rw-r--r-- | chrome/browser/safe_browsing/protocol_parser.cc | 140 | ||||
-rw-r--r-- | chrome/browser/safe_browsing/protocol_parser.h | 18 | ||||
-rw-r--r-- | chrome/browser/safe_browsing/protocol_parser_unittest.cc | 301 | ||||
-rw-r--r-- | chrome/browser/safe_browsing/safe_browsing_database_unittest.cc | 133 |
5 files changed, 443 insertions, 151 deletions
diff --git a/chrome/browser/safe_browsing/protocol_manager.cc b/chrome/browser/safe_browsing/protocol_manager.cc index 69f8583..26abb9a 100644 --- a/chrome/browser/safe_browsing/protocol_manager.cc +++ b/chrome/browser/safe_browsing/protocol_manager.cc @@ -417,7 +417,7 @@ bool SafeBrowsingProtocolManager::HandleServiceResponse(const GURL& url, scoped_ptr<SBChunkList> chunks(new SBChunkList); UMA_HISTOGRAM_COUNTS("SB2.ChunkSize", length); update_size_ += length; - if (!parser.ParseChunk(data, length, + if (!parser.ParseChunk(chunk_url.list_name, data, length, client_key_, chunk_url.mac, &re_key, chunks.get())) { #ifndef NDEBUG diff --git a/chrome/browser/safe_browsing/protocol_parser.cc b/chrome/browser/safe_browsing/protocol_parser.cc index 681253a..c8d1691 100644 --- a/chrome/browser/safe_browsing/protocol_parser.cc +++ b/chrome/browser/safe_browsing/protocol_parser.cc @@ -5,6 +5,7 @@ // Parse the data returned from the SafeBrowsing v2.1 protocol response. #include "chrome/browser/safe_browsing/protocol_parser.h" +#include "chrome/browser/safe_browsing/safe_browsing_util.h" #include "build/build_config.h" @@ -245,7 +246,8 @@ bool SafeBrowsingProtocolParser::ParseUpdate( return true; } -bool SafeBrowsingProtocolParser::ParseChunk(const char* data, +bool SafeBrowsingProtocolParser::ParseChunk(const std::string& list_name, + const char* data, int length, const std::string& key, const std::string& mac, @@ -299,12 +301,12 @@ bool SafeBrowsingProtocolParser::ParseChunk(const char* data, if (cmd_parts[0] == "a") { chunks->back().is_add = true; - if (!ParseAddChunk(chunk_data, chunk_len, hash_len, + if (!ParseAddChunk(list_name, chunk_data, chunk_len, hash_len, &chunks->back().hosts)) return false; // Parse error. } else if (cmd_parts[0] == "s") { chunks->back().is_add = false; - if (!ParseSubChunk(chunk_data, chunk_len, hash_len, + if (!ParseSubChunk(list_name, chunk_data, chunk_len, hash_len, &chunks->back().hosts)) return false; // Parse error. } else { @@ -322,85 +324,88 @@ bool SafeBrowsingProtocolParser::ParseChunk(const char* data, return true; } -bool SafeBrowsingProtocolParser::ParseAddChunk( - const char* data, int data_len, int hash_len, - std::deque<SBChunkHost>* hosts) { - - int remaining = data_len; +bool SafeBrowsingProtocolParser::ParseAddChunk(const std::string& list_name, + const char* data, + int data_len, + int hash_len, + std::deque<SBChunkHost>* hosts) { const char* chunk_data = data; - const int min_size = sizeof(SBPrefix) + 1; - - while (remaining >= min_size) { + int remaining = data_len; + int prefix_count; + SBEntry::Type type = hash_len == sizeof(SBPrefix) ? + SBEntry::ADD_PREFIX : SBEntry::ADD_FULL_HASH; + + if (list_name == safe_browsing_util::kBinHashList) { + // kBinHashList only contains prefixes, no HOSTKEY and COUNT. + DCHECK_EQ(0, remaining % hash_len); + prefix_count = remaining / hash_len; + SBChunkHost chunk_host; + chunk_host.host = 0; + chunk_host.entry = SBEntry::Create(type, prefix_count); + hosts->push_back(chunk_host); + if (!ReadPrefixes(&chunk_data, &remaining, chunk_host.entry, prefix_count)) + return false; + } else { SBPrefix host; - int prefix_count; - ReadHostAndPrefixCount(&chunk_data, &remaining, &host, &prefix_count); - SBEntry::Type type = hash_len == sizeof(SBPrefix) ? - SBEntry::ADD_PREFIX : SBEntry::ADD_FULL_HASH; - SBEntry* entry; - int index_start = 0; - - // If a host has more than 255 prefixes, then subsequent entries are used. - // Check if this is the case, and if so put them in one SBEntry since the - // database code assumes that all prefixes from the same host and chunk are - // in one SBEntry. - if (!hosts->empty() && hosts->back().host == host && - hosts->back().entry->HashLen() == hash_len) { - // Reuse the SBChunkHost, but need to create a new SBEntry since we have - // more prefixes. - index_start = hosts->back().entry->prefix_count(); - entry = hosts->back().entry->Enlarge(prefix_count); - hosts->back().entry = entry; - } else { - entry = SBEntry::Create(type, prefix_count); + const int min_size = sizeof(SBPrefix) + 1; + while (remaining >= min_size) { + ReadHostAndPrefixCount(&chunk_data, &remaining, &host, &prefix_count); SBChunkHost chunk_host; chunk_host.host = host; - chunk_host.entry = entry; + chunk_host.entry = SBEntry::Create(type, prefix_count); hosts->push_back(chunk_host); + if (!ReadPrefixes(&chunk_data, &remaining, chunk_host.entry, + prefix_count)) + return false; } - - if (!ReadPrefixes(&chunk_data, &remaining, entry, prefix_count, - index_start)) - return false; } - return remaining == 0; } -bool SafeBrowsingProtocolParser::ParseSubChunk( - const char* data, int data_len, int hash_len, - std::deque<SBChunkHost>* hosts) { - +bool SafeBrowsingProtocolParser::ParseSubChunk(const std::string& list_name, + const char* data, + int data_len, + int hash_len, + std::deque<SBChunkHost>* hosts) { int remaining = data_len; const char* chunk_data = data; - const int min_size = 2 * sizeof(SBPrefix) + 1; - - while (remaining >= min_size) { - SBPrefix host; - int prefix_count; - ReadHostAndPrefixCount(&chunk_data, &remaining, &host, &prefix_count); - SBEntry::Type type = hash_len == sizeof(SBPrefix) ? - SBEntry::SUB_PREFIX : SBEntry::SUB_FULL_HASH; - SBEntry* entry = SBEntry::Create(type, prefix_count); + int prefix_count; + SBEntry::Type type = hash_len == sizeof(SBPrefix) ? + SBEntry::SUB_PREFIX : SBEntry::SUB_FULL_HASH; + if (list_name == safe_browsing_util::kBinHashList) { SBChunkHost chunk_host; - chunk_host.host = host; - chunk_host.entry = entry; + // Set host to 0 and it won't be used for kBinHashList. + chunk_host.host = 0; + // kBinHashList only contains (add_chunk_number, prefix) pairs, no HOSTKEY + // and COUNT. |add_chunk_number| is int32. + prefix_count = remaining / (sizeof(int32) + hash_len); + chunk_host.entry = SBEntry::Create(type, prefix_count); + if (!ReadPrefixes(&chunk_data, &remaining, chunk_host.entry, prefix_count)) + return false; hosts->push_back(chunk_host); - - if (prefix_count == 0) { - // There is only an add chunk number (no prefixes). - entry->set_chunk_id(ReadChunkId(&chunk_data, &remaining)); - continue; + } else { + SBPrefix host; + const int min_size = 2 * sizeof(SBPrefix) + 1; + while (remaining >= min_size) { + ReadHostAndPrefixCount(&chunk_data, &remaining, &host, &prefix_count); + SBChunkHost chunk_host; + chunk_host.host = host; + chunk_host.entry = SBEntry::Create(type, prefix_count); + hosts->push_back(chunk_host); + if (prefix_count == 0) { + // There is only an add chunk number (no prefixes). + chunk_host.entry->set_chunk_id(ReadChunkId(&chunk_data, &remaining)); + continue; + } + if (!ReadPrefixes(&chunk_data, &remaining, chunk_host.entry, + prefix_count)) + return false; } - - if (!ReadPrefixes(&chunk_data, &remaining, entry, prefix_count, 0)) - return false; } - return remaining == 0; } - void SafeBrowsingProtocolParser::ReadHostAndPrefixCount( const char** data, int* remaining, SBPrefix* host, int* count) { // Next 4 bytes are the host prefix. @@ -424,22 +429,19 @@ int SafeBrowsingProtocolParser::ReadChunkId( } bool SafeBrowsingProtocolParser::ReadPrefixes( - const char** data, int* remaining, SBEntry* entry, int count, - int index_start) { + const char** data, int* remaining, SBEntry* entry, int count) { int hash_len = entry->HashLen(); for (int i = 0; i < count; ++i) { if (entry->IsSub()) { - entry->SetChunkIdAtPrefix(index_start + i, ReadChunkId(data, remaining)); + entry->SetChunkIdAtPrefix(i, ReadChunkId(data, remaining)); if (*remaining <= 0) return false; } if (entry->IsPrefix()) { - entry->SetPrefixAt(index_start + i, - *reinterpret_cast<const SBPrefix*>(*data)); + entry->SetPrefixAt(i, *reinterpret_cast<const SBPrefix*>(*data)); } else { - entry->SetFullHashAt(index_start + i, - *reinterpret_cast<const SBFullHash*>(*data)); + entry->SetFullHashAt(i, *reinterpret_cast<const SBFullHash*>(*data)); } *data += hash_len; *remaining -= hash_len; diff --git a/chrome/browser/safe_browsing/protocol_parser.h b/chrome/browser/safe_browsing/protocol_parser.h index 9384f07..d074f2a 100644 --- a/chrome/browser/safe_browsing/protocol_parser.h +++ b/chrome/browser/safe_browsing/protocol_parser.h @@ -75,7 +75,8 @@ class SafeBrowsingProtocolParser { // Parse the response from a chunk URL request and returns the hosts/prefixes // for adds and subs in "chunks". Returns 'true' on successful parsing, // 'false' otherwise. Any result should be ignored when a parse has failed. - bool ParseChunk(const char* chunk_data, + bool ParseChunk(const std::string& list_name, + const char* chunk_data, int chunk_len, const std::string& key, const std::string& mac, @@ -102,22 +103,25 @@ class SafeBrowsingProtocolParser { std::string* wrapped_key); private: - bool ParseAddChunk(const char* data, + bool ParseAddChunk(const std::string& list_name, + const char* data, int data_len, int hash_len, std::deque<SBChunkHost>* hosts); - bool ParseSubChunk(const char* data, + bool ParseSubChunk(const std::string& list_name, + const char* data, int data_len, int hash_len, std::deque<SBChunkHost>* hosts); // Helper functions used by ParseAddChunk and ParseSubChunk. - static void ReadHostAndPrefixCount( - const char** data, int* remaining, SBPrefix* host, int* count); + static void ReadHostAndPrefixCount(const char** data, + int* remaining, + SBPrefix* host, + int* count); static int ReadChunkId(const char** data, int* remaining); static bool ReadPrefixes( - const char** data, int* remaining, SBEntry* entry, int count, - int index_start); + const char** data, int* remaining, SBEntry* entry, int count); // The name of the current list std::string list_name_; diff --git a/chrome/browser/safe_browsing/protocol_parser_unittest.cc b/chrome/browser/safe_browsing/protocol_parser_unittest.cc index f32a21c..d52b3d6 100644 --- a/chrome/browser/safe_browsing/protocol_parser_unittest.cc +++ b/chrome/browser/safe_browsing/protocol_parser_unittest.cc @@ -6,9 +6,9 @@ #include "base/string_util.h" #include "chrome/browser/safe_browsing/protocol_parser.h" +#include "chrome/browser/safe_browsing/safe_browsing_util.h" #include "testing/gtest/include/gtest/gtest.h" - // Test parsing one add chunk. TEST(SafeBrowsingProtocolParsingTest, TestAddChunk) { std::string add_chunk("a:1:4:35\naaaax1111\0032222333344447777\00288889999"); @@ -18,14 +18,16 @@ TEST(SafeBrowsingProtocolParsingTest, TestAddChunk) { SafeBrowsingProtocolParser parser; bool re_key = false; SBChunkList chunks; - bool result = parser.ParseChunk(add_chunk.data(), - static_cast<int>(add_chunk.length()), - "", "", &re_key, &chunks); + bool result = parser.ParseChunk( + safe_browsing_util::kMalwareList, + add_chunk.data(), + static_cast<int>(add_chunk.length()), + "", "", &re_key, &chunks); EXPECT_TRUE(result); EXPECT_FALSE(re_key); - EXPECT_EQ(chunks.size(), static_cast<size_t>(1)); + EXPECT_EQ(chunks.size(), 1U); EXPECT_EQ(chunks[0].chunk_number, 1); - EXPECT_EQ(chunks[0].hosts.size(), static_cast<size_t>(3)); + EXPECT_EQ(chunks[0].hosts.size(), 3U); EXPECT_EQ(chunks[0].hosts[0].host, 0x61616161); SBEntry* entry = chunks[0].hosts[0].entry; @@ -69,14 +71,16 @@ TEST(SafeBrowsingProtocolParsingTest, TestAddFullChunk) { SafeBrowsingProtocolParser parser; bool re_key = false; SBChunkList chunks; - bool result = parser.ParseChunk(add_chunk.data(), - static_cast<int>(add_chunk.length()), - "", "", &re_key, &chunks); + bool result = parser.ParseChunk( + safe_browsing_util::kMalwareList, + add_chunk.data(), + static_cast<int>(add_chunk.length()), + "", "", &re_key, &chunks); EXPECT_TRUE(result); EXPECT_FALSE(re_key); - EXPECT_EQ(chunks.size(), static_cast<size_t>(1)); + EXPECT_EQ(chunks.size(), 1U); EXPECT_EQ(chunks[0].chunk_number, 1); - EXPECT_EQ(chunks[0].hosts.size(), static_cast<size_t>(1)); + EXPECT_EQ(chunks[0].hosts.size(), 1U); EXPECT_EQ(chunks[0].hosts[0].host, 0x61616161); SBEntry* entry = chunks[0].hosts[0].entry; @@ -98,14 +102,16 @@ TEST(SafeBrowsingProtocolParsingTest, TestAddChunks) { SafeBrowsingProtocolParser parser; bool re_key = false; SBChunkList chunks; - bool result = parser.ParseChunk(add_chunk.data(), - static_cast<int>(add_chunk.length()), - "", "", &re_key, &chunks); + bool result = parser.ParseChunk( + safe_browsing_util::kMalwareList, + add_chunk.data(), + static_cast<int>(add_chunk.length()), + "", "", &re_key, &chunks); EXPECT_TRUE(result); EXPECT_FALSE(re_key); - EXPECT_EQ(chunks.size(), static_cast<size_t>(2)); + EXPECT_EQ(chunks.size(), 2U); EXPECT_EQ(chunks[0].chunk_number, 1); - EXPECT_EQ(chunks[0].hosts.size(), static_cast<size_t>(3)); + EXPECT_EQ(chunks[0].hosts.size(), 3U); EXPECT_EQ(chunks[0].hosts[0].host, 0x61616161); SBEntry* entry = chunks[0].hosts[0].entry; @@ -132,7 +138,7 @@ TEST(SafeBrowsingProtocolParsingTest, TestAddChunks) { EXPECT_EQ(chunks[1].chunk_number, 2); - EXPECT_EQ(chunks[1].hosts.size(), static_cast<size_t>(1)); + EXPECT_EQ(chunks[1].hosts.size(), 1U); EXPECT_EQ(chunks[1].hosts[0].host, 0x35353535); entry = chunks[1].hosts[0].entry; @@ -158,34 +164,77 @@ TEST(SafeBrowsingProtocolParsingTest, TestAddBigChunk) { SafeBrowsingProtocolParser parser; bool re_key = false; SBChunkList chunks; - bool result = parser.ParseChunk(add_chunk.data(), - static_cast<int>(add_chunk.length()), - "", "", &re_key, &chunks); + bool result = parser.ParseChunk( + safe_browsing_util::kMalwareList, + add_chunk.data(), + static_cast<int>(add_chunk.length()), + "", "", &re_key, &chunks); EXPECT_TRUE(result); EXPECT_FALSE(re_key); - EXPECT_EQ(chunks.size(), static_cast<size_t>(1)); + EXPECT_EQ(chunks.size(), 1U); EXPECT_EQ(chunks[0].chunk_number, 1); - EXPECT_EQ(chunks[0].hosts.size(), static_cast<size_t>(1)); + EXPECT_EQ(chunks[0].hosts.size(), 2U); + + const SBChunkHost& host0 = chunks[0].hosts[0]; + EXPECT_EQ(host0.host, 0x61616161); + EXPECT_EQ(host0.entry->prefix_count(), 255); - const SBChunkHost& host = chunks[0].hosts[0]; - EXPECT_EQ(host.host, 0x61616161); - EXPECT_EQ(host.entry->prefix_count(), 260); + const SBChunkHost& host1 = chunks[0].hosts[1]; + EXPECT_EQ(host1.host, 0x61616161); + EXPECT_EQ(host1.entry->prefix_count(), 5); } -// Test to make sure we could deal with truncated chunk. -TEST(SafeBrowsingProtocolParsingTest, TestTruncatedChunk) { +// Test to make sure we could deal with truncated bin hash chunk. +TEST(SafeBrowsingProtocolParsingTest, TestTruncatedBinHashChunk) { + // This chunk delares there are 4 prefixes but actually only contains 2. + const char add_chunk[] = "a:1:4:16\n11112222"; + SafeBrowsingProtocolParser parser; + bool re_key = false; + SBChunkList chunks; + bool result = parser.ParseChunk(add_chunk, + safe_browsing_util::kBinHashList, + static_cast<int>(sizeof(add_chunk)), + "", "", &re_key, &chunks); + EXPECT_FALSE(result); + EXPECT_FALSE(re_key); + EXPECT_EQ(chunks.size(), 0U); +} + +// Test to make sure we could deal with truncated malwarelist chunk. +TEST(SafeBrowsingProtocolParsingTest, TestTruncatedUrlHashChunk) { // This chunk delares there are 4 prefixes but actually only contains 2. const char add_chunk[] = "a:1:4:21\naaaa\00411112222"; SafeBrowsingProtocolParser parser; bool re_key = false; SBChunkList chunks; + + // For safe_browsing_util::kMalwareList. bool result = parser.ParseChunk(add_chunk, + safe_browsing_util::kMalwareList, static_cast<int>(sizeof(add_chunk)), "", "", &re_key, &chunks); EXPECT_FALSE(result); EXPECT_FALSE(re_key); EXPECT_EQ(chunks.size(), 0U); + + // For safe_browsing_util::kPhishingList. + result = parser.ParseChunk(add_chunk, + safe_browsing_util::kPhishingList, + static_cast<int>(sizeof(add_chunk)), + "", "", &re_key, &chunks); + EXPECT_FALSE(result); + EXPECT_FALSE(re_key); + EXPECT_EQ(chunks.size(), 0U); + + // For safe_browsing_util::kBinUrlList. + result = parser.ParseChunk(add_chunk, + safe_browsing_util::kBinUrlList, + static_cast<int>(sizeof(add_chunk)), + "", "", &re_key, &chunks); + EXPECT_FALSE(result); + EXPECT_FALSE(re_key); + EXPECT_EQ(chunks.size(), 0U); } // Test parsing one sub chunk. @@ -199,14 +248,16 @@ TEST(SafeBrowsingProtocolParsingTest, TestSubChunk) { SafeBrowsingProtocolParser parser; bool re_key = false; SBChunkList chunks; - bool result = parser.ParseChunk(sub_chunk.data(), - static_cast<int>(sub_chunk.length()), - "", "", &re_key, &chunks); + bool result = parser.ParseChunk( + safe_browsing_util::kMalwareList, + sub_chunk.data(), + static_cast<int>(sub_chunk.length()), + "", "", &re_key, &chunks); EXPECT_TRUE(result); EXPECT_FALSE(re_key); - EXPECT_EQ(chunks.size(), static_cast<size_t>(1)); + EXPECT_EQ(chunks.size(), 1U); EXPECT_EQ(chunks[0].chunk_number, 9); - EXPECT_EQ(chunks[0].hosts.size(), static_cast<size_t>(3)); + EXPECT_EQ(chunks[0].hosts.size(), 3U); EXPECT_EQ(chunks[0].hosts[0].host, 0x61616161); SBEntry* entry = chunks[0].hosts[0].entry; @@ -258,14 +309,16 @@ TEST(SafeBrowsingProtocolParsingTest, TestSubFullChunk) { SafeBrowsingProtocolParser parser; bool re_key = false; SBChunkList chunks; - bool result = parser.ParseChunk(sub_chunk.data(), - static_cast<int>(sub_chunk.length()), - "", "", &re_key, &chunks); + bool result = parser.ParseChunk( + safe_browsing_util::kMalwareList, + sub_chunk.data(), + static_cast<int>(sub_chunk.length()), + "", "", &re_key, &chunks); EXPECT_TRUE(result); EXPECT_FALSE(re_key); - EXPECT_EQ(chunks.size(), static_cast<size_t>(1)); + EXPECT_EQ(chunks.size(), 1U); EXPECT_EQ(chunks[0].chunk_number, 1); - EXPECT_EQ(chunks[0].hosts.size(), static_cast<size_t>(1)); + EXPECT_EQ(chunks[0].hosts.size(), 1U); EXPECT_EQ(chunks[0].hosts[0].host, 0x61616161); SBEntry* entry = chunks[0].hosts[0].entry; @@ -298,15 +351,15 @@ TEST(SafeBrowsingProtocolParsingTest, TestChunkDelete) { EXPECT_FALSE(re_key); EXPECT_FALSE(reset); EXPECT_EQ(next_query_sec, 1700); - EXPECT_EQ(deletes.size(), static_cast<size_t>(2)); + EXPECT_EQ(deletes.size(), 2U); - EXPECT_EQ(deletes[0].chunk_del.size(), static_cast<size_t>(4)); + EXPECT_EQ(deletes[0].chunk_del.size(), 4U); EXPECT_TRUE(deletes[0].chunk_del[0] == ChunkRange(1, 7)); EXPECT_TRUE(deletes[0].chunk_del[1] == ChunkRange(43, 597)); EXPECT_TRUE(deletes[0].chunk_del[2] == ChunkRange(44444)); EXPECT_TRUE(deletes[0].chunk_del[3] == ChunkRange(99999)); - EXPECT_EQ(deletes[1].chunk_del.size(), static_cast<size_t>(3)); + EXPECT_EQ(deletes[1].chunk_del.size(), 3U); EXPECT_TRUE(deletes[1].chunk_del[0] == ChunkRange(21, 27)); EXPECT_TRUE(deletes[1].chunk_del[1] == ChunkRange(42)); EXPECT_TRUE(deletes[1].chunk_del[2] == ChunkRange(171717)); @@ -345,7 +398,7 @@ TEST(SafeBrowsingProtocolParsingTest, TestRedirects) { EXPECT_FALSE(re_key); EXPECT_FALSE(reset); - EXPECT_EQ(urls.size(), static_cast<size_t>(4)); + EXPECT_EQ(urls.size(), 4U); EXPECT_EQ(urls[0].url, "cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_1"); EXPECT_EQ(urls[1].url, @@ -381,7 +434,7 @@ TEST(SafeBrowsingProtocolParsingTest, TestRedirectsWithMac) { EXPECT_FALSE(re_key); EXPECT_FALSE(reset); - EXPECT_EQ(urls.size(), static_cast<size_t>(2)); + EXPECT_EQ(urls.size(), 2U); EXPECT_EQ(urls[0].url, "s.ytimg.com/safebrowsing/rd/goog-phish-shavar_s_6501-6505:6501-6505"); EXPECT_EQ(urls[0].mac, "pcY6iVeT9-CBQ3fdAF0rpnKjR1Y="); @@ -427,7 +480,7 @@ TEST(SafeBrowsingProtocolParsingTest, TestGetHash) { &full_hashes)); EXPECT_FALSE(re_key); - EXPECT_EQ(full_hashes.size(), static_cast<size_t>(3)); + EXPECT_EQ(full_hashes.size(), 3U); EXPECT_EQ(memcmp(&full_hashes[0].hash, "00112233445566778899aabbccddeeff", sizeof(SBFullHash)), 0); @@ -453,7 +506,7 @@ TEST(SafeBrowsingProtocolParsingTest, TestGetHash) { &full_hashes)); EXPECT_FALSE(re_key); - EXPECT_EQ(full_hashes.size(), static_cast<size_t>(3)); + EXPECT_EQ(full_hashes.size(), 3U); EXPECT_EQ(memcmp(&full_hashes[0].hash, "00112233445566778899aabbccddeeff", sizeof(SBFullHash)), 0); @@ -500,7 +553,7 @@ TEST(SafeBrowsingProtocolParsingTest, TestGetHashWithMac) { &re_key, &full_hashes)); EXPECT_FALSE(re_key); - EXPECT_EQ(full_hashes.size(), static_cast<size_t>(1)); + EXPECT_EQ(full_hashes.size(), 1U); EXPECT_EQ(memcmp(hash_result, &full_hashes[0].hash, sizeof(SBFullHash)), 0); } @@ -519,7 +572,7 @@ TEST(SafeBrowsingProtocolParsingTest, TestGetHashWithUnknownList) { &re_key, &full_hashes)); - EXPECT_EQ(full_hashes.size(), static_cast<size_t>(1)); + EXPECT_EQ(full_hashes.size(), 1U); EXPECT_EQ(memcmp("12345678901234567890123456789012", &full_hashes[0].hash, sizeof(SBFullHash)), 0); EXPECT_EQ(full_hashes[0].list_name, "goog-phish-shavar"); @@ -534,7 +587,7 @@ TEST(SafeBrowsingProtocolParsingTest, TestGetHashWithUnknownList) { &re_key, &full_hashes)); - EXPECT_EQ(full_hashes.size(), static_cast<size_t>(2)); + EXPECT_EQ(full_hashes.size(), 2U); EXPECT_EQ(memcmp("12345678901234567890123456789012", &full_hashes[0].hash, sizeof(SBFullHash)), 0); EXPECT_EQ(full_hashes[0].list_name, "goog-phish-shavar"); @@ -614,38 +667,42 @@ TEST(SafeBrowsingProtocolParsingTest, TestZeroSizeAddChunk) { bool re_key = false; SBChunkList chunks; - bool result = parser.ParseChunk(add_chunk.data(), - static_cast<int>(add_chunk.length()), - "", "", &re_key, &chunks); + bool result = parser.ParseChunk( + safe_browsing_util::kMalwareList, + add_chunk.data(), + static_cast<int>(add_chunk.length()), + "", "", &re_key, &chunks); EXPECT_TRUE(result); - EXPECT_EQ(chunks.size(), static_cast<size_t>(1)); + EXPECT_EQ(chunks.size(), 1U); EXPECT_EQ(chunks[0].chunk_number, 1); - EXPECT_EQ(chunks[0].hosts.size(), static_cast<size_t>(0)); + EXPECT_EQ(chunks[0].hosts.size(), 0U); // Now test a zero size chunk in between normal chunks. chunks.clear(); std::string add_chunks("a:1:4:18\n1234\001abcd5678\001wxyz" "a:2:4:0\n" "a:3:4:9\ncafe\001beef"); - result = parser.ParseChunk(add_chunks.data(), - static_cast<int>(add_chunks.length()), - "", "", &re_key, &chunks); + result = parser.ParseChunk( + safe_browsing_util::kMalwareList, + add_chunks.data(), + static_cast<int>(add_chunks.length()), + "", "", &re_key, &chunks); EXPECT_TRUE(result); - EXPECT_EQ(chunks.size(), static_cast<size_t>(3)); + EXPECT_EQ(chunks.size(), 3U); // See that each chunk has the right content. EXPECT_EQ(chunks[0].chunk_number, 1); - EXPECT_EQ(chunks[0].hosts.size(), static_cast<size_t>(2)); + EXPECT_EQ(chunks[0].hosts.size(), 2U); EXPECT_EQ(chunks[0].hosts[0].host, 0x34333231); EXPECT_EQ(chunks[0].hosts[0].entry->PrefixAt(0), 0x64636261); EXPECT_EQ(chunks[0].hosts[1].host, 0x38373635); EXPECT_EQ(chunks[0].hosts[1].entry->PrefixAt(0), 0x7a797877); EXPECT_EQ(chunks[1].chunk_number, 2); - EXPECT_EQ(chunks[1].hosts.size(), static_cast<size_t>(0)); + EXPECT_EQ(chunks[1].hosts.size(), 0U); EXPECT_EQ(chunks[2].chunk_number, 3); - EXPECT_EQ(chunks[2].hosts.size(), static_cast<size_t>(1)); + EXPECT_EQ(chunks[2].hosts.size(), 1U); EXPECT_EQ(chunks[2].hosts[0].host, 0x65666163); EXPECT_EQ(chunks[2].hosts[0].entry->PrefixAt(0), 0x66656562); } @@ -657,13 +714,15 @@ TEST(SafeBrowsingProtocolParsingTest, TestZeroSizeSubChunk) { bool re_key = false; SBChunkList chunks; - bool result = parser.ParseChunk(sub_chunk.data(), - static_cast<int>(sub_chunk.length()), - "", "", &re_key, &chunks); + bool result = parser.ParseChunk( + safe_browsing_util::kMalwareList, + sub_chunk.data(), + static_cast<int>(sub_chunk.length()), + "", "", &re_key, &chunks); EXPECT_TRUE(result); - EXPECT_EQ(chunks.size(), static_cast<size_t>(1)); + EXPECT_EQ(chunks.size(), 1U); EXPECT_EQ(chunks[0].chunk_number, 9); - EXPECT_EQ(chunks[0].hosts.size(), static_cast<size_t>(0)); + EXPECT_EQ(chunks[0].hosts.size(), 0U); chunks.clear(); // Test parsing a zero sized sub chunk mixed in with content carrying chunks. @@ -672,21 +731,23 @@ TEST(SafeBrowsingProtocolParsingTest, TestZeroSizeSubChunk) { "s:3:4:26\nefgh\0011234pqrscafe\0015678lmno"); sub_chunks[12] = '\0'; - result = parser.ParseChunk(sub_chunks.data(), - static_cast<int>(sub_chunks.length()), - "", "", &re_key, &chunks); + result = parser.ParseChunk( + safe_browsing_util::kMalwareList, + sub_chunks.data(), + static_cast<int>(sub_chunks.length()), + "", "", &re_key, &chunks); EXPECT_TRUE(result); EXPECT_EQ(chunks[0].chunk_number, 1); - EXPECT_EQ(chunks[0].hosts.size(), static_cast<size_t>(1)); + EXPECT_EQ(chunks[0].hosts.size(), 1U); EXPECT_EQ(chunks[0].hosts[0].host, 0x64636261); EXPECT_EQ(chunks[0].hosts[0].entry->prefix_count(), 0); EXPECT_EQ(chunks[1].chunk_number, 2); - EXPECT_EQ(chunks[1].hosts.size(), static_cast<size_t>(0)); + EXPECT_EQ(chunks[1].hosts.size(), 0U); EXPECT_EQ(chunks[2].chunk_number, 3); - EXPECT_EQ(chunks[2].hosts.size(), static_cast<size_t>(2)); + EXPECT_EQ(chunks[2].hosts.size(), 2U); EXPECT_EQ(chunks[2].hosts[0].host, 0x68676665); EXPECT_EQ(chunks[2].hosts[0].entry->prefix_count(), 1); EXPECT_EQ(chunks[2].hosts[0].entry->PrefixAt(0), 0x73727170); @@ -764,8 +825,102 @@ TEST(SafeBrowsingProtocolParsingTest, TestVerifyChunkMac) { const std::string key("v_aDSz6jI92WeHCOoZ07QA=="); const std::string mac("W9Xp2fUcQ9V66If6Cvsrstpa4Kk="); - EXPECT_TRUE(parser.ParseChunk(reinterpret_cast<const char*>(chunk), - sizeof(chunk), key, mac, - &re_key, &chunks)); + EXPECT_TRUE(parser.ParseChunk( + safe_browsing_util::kMalwareList, + reinterpret_cast<const char*>(chunk), + sizeof(chunk), key, mac, + &re_key, &chunks)); + EXPECT_FALSE(re_key); +} + +TEST(SafeBrowsingProtocolParsingTest, TestAddBinHashChunks) { + std::string add_chunk("a:1:4:16\naaaabbbbccccdddd" + "a:2:4:8\n11112222"); + // Run the parse. + SafeBrowsingProtocolParser parser; + bool re_key = false; + SBChunkList chunks; + bool result = parser.ParseChunk( + safe_browsing_util::kBinHashList, + add_chunk.data(), + static_cast<int>(add_chunk.length()), + "", "", &re_key, &chunks); + EXPECT_TRUE(result); + EXPECT_FALSE(re_key); + EXPECT_EQ(chunks.size(), 2U); + EXPECT_EQ(chunks[0].chunk_number, 1); + EXPECT_EQ(chunks[0].hosts.size(), 1U); + + EXPECT_EQ(chunks[0].hosts[0].host, 0); + SBEntry* entry = chunks[0].hosts[0].entry; + EXPECT_TRUE(entry->IsAdd()); + EXPECT_TRUE(entry->IsPrefix()); + EXPECT_EQ(entry->prefix_count(), 4); + + EXPECT_EQ(chunks[1].chunk_number, 2); + EXPECT_EQ(chunks[1].hosts.size(), 1U); + + EXPECT_EQ(chunks[1].hosts[0].host, 0); + entry = chunks[1].hosts[0].entry; + EXPECT_TRUE(entry->IsAdd()); + EXPECT_TRUE(entry->IsPrefix()); + EXPECT_EQ(entry->prefix_count(), 2); + EXPECT_EQ(entry->PrefixAt(0), 0x31313131); + EXPECT_EQ(entry->PrefixAt(1), 0x32323232); +} + +// Test parsing one add chunk where a hostkey spans several entries. +TEST(SafeBrowsingProtocolParsingTest, TestAddBigBinHashChunk) { + std::string add_chunk("a:1:4:1028\n"); + for (int i = 0; i < 257; ++i) + add_chunk.append(StringPrintf("%04d", i)); + + SafeBrowsingProtocolParser parser; + bool re_key = false; + SBChunkList chunks; + bool result = parser.ParseChunk( + safe_browsing_util::kBinHashList, + add_chunk.data(), + static_cast<int>(add_chunk.length()), + "", "", &re_key, &chunks); + EXPECT_TRUE(result); + EXPECT_FALSE(re_key); + EXPECT_EQ(chunks.size(), 1U); + EXPECT_EQ(chunks[0].chunk_number, 1); + + EXPECT_EQ(chunks[0].hosts.size(), 1U); + + const SBChunkHost& host0 = chunks[0].hosts[0]; + EXPECT_EQ(host0.host, 0); + EXPECT_EQ(host0.entry->prefix_count(), 257); +} + +// Test parsing one sub chunk. +TEST(SafeBrowsingProtocolParsingTest, TestSubBinHashChunk) { + std::string sub_chunk("s:9:4:16\n1111mmmm2222nnnn"); + + // Run the parser. + SafeBrowsingProtocolParser parser; + bool re_key = false; + SBChunkList chunks; + bool result = parser.ParseChunk( + safe_browsing_util::kBinHashList, + sub_chunk.data(), + static_cast<int>(sub_chunk.length()), + "", "", &re_key, &chunks); + EXPECT_TRUE(result); EXPECT_FALSE(re_key); + EXPECT_EQ(chunks.size(), 1U); + EXPECT_EQ(chunks[0].chunk_number, 9); + EXPECT_EQ(chunks[0].hosts.size(), 1U); + + EXPECT_EQ(chunks[0].hosts[0].host, 0); + SBEntry* entry = chunks[0].hosts[0].entry; + EXPECT_TRUE(entry->IsSub()); + EXPECT_TRUE(entry->IsPrefix()); + EXPECT_EQ(entry->prefix_count(), 2); + EXPECT_EQ(entry->ChunkIdAtPrefix(0), 0x31313131); + EXPECT_EQ(entry->PrefixAt(0), 0x6d6d6d6d); + EXPECT_EQ(entry->ChunkIdAtPrefix(1), 0x32323232); + EXPECT_EQ(entry->PrefixAt(1), 0x6e6e6e6e); } diff --git a/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc b/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc index 249c44c..2b754ef 100644 --- a/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc +++ b/chrome/browser/safe_browsing/safe_browsing_database_unittest.cc @@ -431,7 +431,6 @@ TEST_F(SafeBrowsingDatabaseTest, ListNameForBrowseAndDownload) { InsertAddChunkHostPrefixUrl(&chunk, 1, "www.evil.com/", "www.evil.com/malware.html"); chunks.push_back(chunk); - std::vector<SBListChunkRanges> lists; EXPECT_TRUE(database_->UpdateStarted(&lists)); database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); @@ -1290,3 +1289,135 @@ TEST_F(SafeBrowsingDatabaseTest, ContainsDownloadUrl) { EXPECT_EQ(prefix_hits.size(), 0U); database_.reset(); } + +// Test to make sure we could insert chunk list that +// contains entries for the same host. +TEST_F(SafeBrowsingDatabaseTest, SameHostEntriesOkay) { + SBChunk chunk; + + // Add a malware add chunk with two entries of the same host. + InsertAddChunkHostPrefixUrl(&chunk, 1, "www.evil.com/", + "www.evil.com/malware1.html"); + InsertAddChunkHostPrefixUrl(&chunk, 1, "www.evil.com/", + "www.evil.com/malware2.html"); + SBChunkList chunks; + chunks.push_back(chunk); + + // Insert the testing chunks into database. + std::vector<SBListChunkRanges> lists; + EXPECT_TRUE(database_->UpdateStarted(&lists)); + database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); + database_->UpdateFinished(true); + + GetListsInfo(&lists); + EXPECT_EQ(std::string(safe_browsing_util::kMalwareList), lists[0].name); + EXPECT_EQ("1", lists[0].adds); + EXPECT_TRUE(lists[0].subs.empty()); + + // Add a phishing add chunk with two entries of the same host. + chunk.hosts.clear(); + InsertAddChunkHostPrefixUrl(&chunk, 47, "www.evil.com/", + "www.evil.com/phishing1.html"); + InsertAddChunkHostPrefixUrl(&chunk, 47, "www.evil.com/", + "www.evil.com/phishing2.html"); + chunks.clear(); + chunks.push_back(chunk); + + EXPECT_TRUE(database_->UpdateStarted(&lists)); + database_->InsertChunks(safe_browsing_util::kPhishingList, chunks); + database_->UpdateFinished(true); + + GetListsInfo(&lists); + EXPECT_EQ(std::string(safe_browsing_util::kMalwareList), lists[0].name); + EXPECT_EQ("1", lists[0].adds); + EXPECT_EQ(std::string(safe_browsing_util::kPhishingList), lists[1].name); + EXPECT_EQ("47", lists[1].adds); + + const Time now = Time::Now(); + std::vector<SBPrefix> prefixes; + std::vector<SBFullHashResult> full_hashes; + std::vector<SBPrefix> prefix_hits; + std::string matching_list; + std::string listname; + + EXPECT_TRUE(database_->ContainsBrowseUrl( + GURL("http://www.evil.com/malware1.html"), + &listname, &prefixes, &full_hashes, now)); + EXPECT_TRUE(database_->ContainsBrowseUrl( + GURL("http://www.evil.com/malware2.html"), + &listname, &prefixes, &full_hashes, now)); + EXPECT_TRUE(database_->ContainsBrowseUrl( + GURL("http://www.evil.com/phishing1.html"), + &listname, &prefixes, &full_hashes, now)); + EXPECT_TRUE(database_->ContainsBrowseUrl( + GURL("http://www.evil.com/phishing2.html"), + &listname, &prefixes, &full_hashes, now)); + + // Test removing a single prefix from the add chunk. + // Remove the prefix that added first. + chunk.hosts.clear(); + InsertSubChunkHostPrefixUrl(&chunk, 4, 1, "www.evil.com/", + "www.evil.com/malware1.html"); + chunks.clear(); + chunks.push_back(chunk); + EXPECT_TRUE(database_->UpdateStarted(&lists)); + database_->InsertChunks(safe_browsing_util::kMalwareList, chunks); + database_->UpdateFinished(true); + + // Remove the prefix that added last. + chunk.hosts.clear(); + InsertSubChunkHostPrefixUrl(&chunk, 5, 47, "www.evil.com/", + "www.evil.com/phishing2.html"); + chunks.clear(); + chunks.push_back(chunk); + EXPECT_TRUE(database_->UpdateStarted(&lists)); + database_->InsertChunks(safe_browsing_util::kPhishingList, chunks); + database_->UpdateFinished(true); + + // Verify that the database contains urls expected. + EXPECT_FALSE(database_->ContainsBrowseUrl( + GURL("http://www.evil.com/malware1.html"), + &listname, &prefixes, &full_hashes, now)); + EXPECT_TRUE(database_->ContainsBrowseUrl( + GURL("http://www.evil.com/malware2.html"), + &listname, &prefixes, &full_hashes, now)); + EXPECT_TRUE(database_->ContainsBrowseUrl( + GURL("http://www.evil.com/phishing1.html"), + &listname, &prefixes, &full_hashes, now)); + EXPECT_FALSE(database_->ContainsBrowseUrl( + GURL("http://www.evil.com/phishing2.html"), + &listname, &prefixes, &full_hashes, now)); +} + +TEST_F(SafeBrowsingDatabaseTest, BinHashEntries) { + database_.reset(); + MessageLoop loop(MessageLoop::TYPE_DEFAULT); + SafeBrowsingStoreFile* browse_store = new SafeBrowsingStoreFile(); + SafeBrowsingStoreFile* download_store = new SafeBrowsingStoreFile(); + database_.reset(new SafeBrowsingDatabaseNew(browse_store, download_store)); + database_->Init(database_filename_); + + SBChunkList chunks; + SBChunk chunk; + // Insert one host. + InsertAddChunkHostPrefixValue(&chunk, 1, 0, 0x31313131); + // Insert a second host, which has the same host prefix as the first one. + InsertAddChunkHostPrefixValue(&chunk, 1, 0, 0x32323232); + chunks.push_back(chunk); + + // Insert the testing chunks into database. + std::vector<SBListChunkRanges> lists; + EXPECT_TRUE(database_->UpdateStarted(&lists)); + database_->InsertChunks(safe_browsing_util::kBinHashList, chunks); + database_->UpdateFinished(true); + + GetListsInfo(&lists); + ASSERT_EQ(4U, lists.size()); + EXPECT_EQ(std::string(safe_browsing_util::kBinHashList), lists[3].name); + EXPECT_EQ("1", lists[3].adds); + EXPECT_TRUE(lists[3].subs.empty()); + + // TODO(lzheng): Query database and verifies the prefixes once that API + // database is available in database. + database_.reset(); +} |