Home | History | Annotate | Download | only in safe_browsing
      1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 //
      5 // Program to test the SafeBrowsing protocol parsing v2.1.
      6 
      7 #include "base/strings/stringprintf.h"
      8 #include "chrome/browser/safe_browsing/protocol_parser.h"
      9 #include "chrome/browser/safe_browsing/safe_browsing_util.h"
     10 #include "testing/gtest/include/gtest/gtest.h"
     11 
     12 // Test parsing one add chunk.
     13 TEST(SafeBrowsingProtocolParsingTest, TestAddChunk) {
     14   std::string add_chunk("a:1:4:35\naaaax1111\0032222333344447777\00288889999");
     15   add_chunk[13] = '\0';
     16 
     17   // Run the parse.
     18   SafeBrowsingProtocolParser parser;
     19   SBChunkList chunks;
     20   bool result = parser.ParseChunk(
     21       safe_browsing_util::kMalwareList,
     22       add_chunk.data(),
     23       static_cast<int>(add_chunk.length()),
     24       &chunks);
     25   EXPECT_TRUE(result);
     26   EXPECT_EQ(chunks.size(), 1U);
     27   EXPECT_EQ(chunks[0].chunk_number, 1);
     28   EXPECT_EQ(chunks[0].hosts.size(), 3U);
     29 
     30   EXPECT_EQ(chunks[0].hosts[0].host, 0x61616161);
     31   SBEntry* entry = chunks[0].hosts[0].entry;
     32   EXPECT_TRUE(entry->IsAdd());
     33   EXPECT_TRUE(entry->IsPrefix());
     34   EXPECT_EQ(entry->prefix_count(), 0);
     35 
     36   EXPECT_EQ(chunks[0].hosts[1].host, 0x31313131);
     37   entry = chunks[0].hosts[1].entry;
     38   EXPECT_TRUE(entry->IsAdd());
     39   EXPECT_TRUE(entry->IsPrefix());
     40   EXPECT_EQ(entry->prefix_count(), 3);
     41   EXPECT_EQ(entry->PrefixAt(0), 0x32323232);
     42   EXPECT_EQ(entry->PrefixAt(1), 0x33333333);
     43   EXPECT_EQ(entry->PrefixAt(2), 0x34343434);
     44 
     45   EXPECT_EQ(chunks[0].hosts[2].host, 0x37373737);
     46   entry = chunks[0].hosts[2].entry;
     47   EXPECT_TRUE(entry->IsAdd());
     48   EXPECT_TRUE(entry->IsPrefix());
     49   EXPECT_EQ(entry->prefix_count(), 2);
     50   EXPECT_EQ(entry->PrefixAt(0), 0x38383838);
     51   EXPECT_EQ(entry->PrefixAt(1), 0x39393939);
     52 }
     53 
     54 // Test parsing one add chunk with full hashes.
     55 TEST(SafeBrowsingProtocolParsingTest, TestAddFullChunk) {
     56   std::string add_chunk("a:1:32:69\naaaa");
     57   add_chunk.push_back(2);
     58 
     59   SBFullHash full_hash1, full_hash2;
     60   for (int i = 0; i < 32; ++i) {
     61     full_hash1.full_hash[i] = i % 2 ? 1 : 2;
     62     full_hash2.full_hash[i] = i % 2 ? 3 : 4;
     63   }
     64 
     65   add_chunk.append(full_hash1.full_hash, 32);
     66   add_chunk.append(full_hash2.full_hash, 32);
     67 
     68   // Run the parse.
     69   SafeBrowsingProtocolParser parser;
     70   SBChunkList chunks;
     71   bool result = parser.ParseChunk(
     72       safe_browsing_util::kMalwareList,
     73       add_chunk.data(),
     74       static_cast<int>(add_chunk.length()),
     75       &chunks);
     76   EXPECT_TRUE(result);
     77   EXPECT_EQ(chunks.size(), 1U);
     78   EXPECT_EQ(chunks[0].chunk_number, 1);
     79   EXPECT_EQ(chunks[0].hosts.size(), 1U);
     80 
     81   EXPECT_EQ(chunks[0].hosts[0].host, 0x61616161);
     82   SBEntry* entry = chunks[0].hosts[0].entry;
     83   EXPECT_TRUE(entry->IsAdd());
     84   EXPECT_FALSE(entry->IsPrefix());
     85   EXPECT_EQ(entry->prefix_count(), 2);
     86   EXPECT_TRUE(entry->FullHashAt(0) == full_hash1);
     87   EXPECT_TRUE(entry->FullHashAt(1) == full_hash2);
     88 }
     89 
     90 // Test parsing multiple add chunks. We'll use the same chunk as above, and add
     91 // one more after it.
     92 TEST(SafeBrowsingProtocolParsingTest, TestAddChunks) {
     93   std::string add_chunk("a:1:4:35\naaaax1111\0032222333344447777\00288889999"
     94                         "a:2:4:13\n5555\002ppppgggg");
     95   add_chunk[13] = '\0';
     96 
     97   // Run the parse.
     98   SafeBrowsingProtocolParser parser;
     99   SBChunkList chunks;
    100   bool result = parser.ParseChunk(
    101       safe_browsing_util::kMalwareList,
    102       add_chunk.data(),
    103       static_cast<int>(add_chunk.length()),
    104       &chunks);
    105   EXPECT_TRUE(result);
    106   EXPECT_EQ(chunks.size(), 2U);
    107   EXPECT_EQ(chunks[0].chunk_number, 1);
    108   EXPECT_EQ(chunks[0].hosts.size(), 3U);
    109 
    110   EXPECT_EQ(chunks[0].hosts[0].host, 0x61616161);
    111   SBEntry* entry = chunks[0].hosts[0].entry;
    112   EXPECT_TRUE(entry->IsAdd());
    113   EXPECT_TRUE(entry->IsPrefix());
    114   EXPECT_EQ(entry->prefix_count(), 0);
    115 
    116   EXPECT_EQ(chunks[0].hosts[1].host, 0x31313131);
    117   entry = chunks[0].hosts[1].entry;
    118   EXPECT_TRUE(entry->IsAdd());
    119   EXPECT_TRUE(entry->IsPrefix());
    120   EXPECT_EQ(entry->prefix_count(), 3);
    121   EXPECT_EQ(entry->PrefixAt(0), 0x32323232);
    122   EXPECT_EQ(entry->PrefixAt(1), 0x33333333);
    123   EXPECT_EQ(entry->PrefixAt(2), 0x34343434);
    124 
    125   EXPECT_EQ(chunks[0].hosts[2].host, 0x37373737);
    126   entry = chunks[0].hosts[2].entry;
    127   EXPECT_TRUE(entry->IsAdd());
    128   EXPECT_TRUE(entry->IsPrefix());
    129   EXPECT_EQ(entry->prefix_count(), 2);
    130   EXPECT_EQ(entry->PrefixAt(0), 0x38383838);
    131   EXPECT_EQ(entry->PrefixAt(1), 0x39393939);
    132 
    133 
    134   EXPECT_EQ(chunks[1].chunk_number, 2);
    135   EXPECT_EQ(chunks[1].hosts.size(), 1U);
    136 
    137   EXPECT_EQ(chunks[1].hosts[0].host, 0x35353535);
    138   entry = chunks[1].hosts[0].entry;
    139   EXPECT_TRUE(entry->IsAdd());
    140   EXPECT_TRUE(entry->IsPrefix());
    141   EXPECT_EQ(entry->prefix_count(), 2);
    142   EXPECT_EQ(entry->PrefixAt(0), 0x70707070);
    143   EXPECT_EQ(entry->PrefixAt(1), 0x67676767);
    144 }
    145 
    146 // Test parsing one add chunk where a hostkey spans several entries.
    147 TEST(SafeBrowsingProtocolParsingTest, TestAddBigChunk) {
    148   std::string add_chunk("a:1:4:1050\naaaaX");
    149   add_chunk[add_chunk.size() - 1] |= 0xFF;
    150   for (int i = 0; i < 255; ++i)
    151     add_chunk.append(base::StringPrintf("%04d", i));
    152 
    153   add_chunk.append("aaaa");
    154   add_chunk.push_back(5);
    155   for (int i = 0; i < 5; ++i)
    156     add_chunk.append(base::StringPrintf("001%d", i));
    157 
    158   SafeBrowsingProtocolParser parser;
    159   SBChunkList chunks;
    160   bool result = parser.ParseChunk(
    161       safe_browsing_util::kMalwareList,
    162       add_chunk.data(),
    163       static_cast<int>(add_chunk.length()),
    164       &chunks);
    165   EXPECT_TRUE(result);
    166   EXPECT_EQ(chunks.size(), 1U);
    167   EXPECT_EQ(chunks[0].chunk_number, 1);
    168 
    169   EXPECT_EQ(chunks[0].hosts.size(), 2U);
    170 
    171   const SBChunkHost& host0 = chunks[0].hosts[0];
    172   EXPECT_EQ(host0.host, 0x61616161);
    173   EXPECT_EQ(host0.entry->prefix_count(), 255);
    174 
    175   const SBChunkHost& host1 = chunks[0].hosts[1];
    176   EXPECT_EQ(host1.host, 0x61616161);
    177   EXPECT_EQ(host1.entry->prefix_count(), 5);
    178 }
    179 
    180 // Test to make sure we could deal with truncated bin hash chunk.
    181 TEST(SafeBrowsingProtocolParsingTest, TestTruncatedBinHashChunk) {
    182   // This chunk delares there are 4 prefixes but actually only contains 2.
    183   const char add_chunk[] = "a:1:4:16\n11112222";
    184   SafeBrowsingProtocolParser parser;
    185   SBChunkList chunks;
    186   bool result = parser.ParseChunk(safe_browsing_util::kBinHashList,
    187                                   add_chunk,
    188                                   static_cast<int>(sizeof(add_chunk)),
    189                                   &chunks);
    190   EXPECT_FALSE(result);
    191   EXPECT_EQ(chunks.size(), 0U);
    192 }
    193 
    194 // Test to make sure we could deal with truncated malwarelist chunk.
    195 TEST(SafeBrowsingProtocolParsingTest, TestTruncatedUrlHashChunk) {
    196   // This chunk delares there are 4 prefixes but actually only contains 2.
    197   const char add_chunk[] = "a:1:4:21\naaaa\00411112222";
    198   SafeBrowsingProtocolParser parser;
    199   SBChunkList chunks;
    200 
    201   // For safe_browsing_util::kMalwareList.
    202   bool result = parser.ParseChunk(safe_browsing_util::kMalwareList,
    203                                   add_chunk,
    204                                   static_cast<int>(sizeof(add_chunk)),
    205                                   &chunks);
    206   EXPECT_FALSE(result);
    207   EXPECT_EQ(chunks.size(), 0U);
    208 
    209   // For safe_browsing_util::kPhishingList.
    210   result = parser.ParseChunk(safe_browsing_util::kPhishingList,
    211                              add_chunk,
    212                              static_cast<int>(sizeof(add_chunk)),
    213                              &chunks);
    214   EXPECT_FALSE(result);
    215   EXPECT_EQ(chunks.size(), 0U);
    216 
    217   // For safe_browsing_util::kBinUrlList.
    218   result = parser.ParseChunk(safe_browsing_util::kBinUrlList,
    219                              add_chunk,
    220                              static_cast<int>(sizeof(add_chunk)),
    221                              &chunks);
    222   EXPECT_FALSE(result);
    223   EXPECT_EQ(chunks.size(), 0U);
    224 }
    225 
    226 // Test to verify handling of a truncated chunk header.
    227 TEST(SafeBrowsingProtocolParsingTest, TestTruncatedHeader) {
    228   std::string truncated_chunks("a:1:4:0\na:");
    229 
    230   // Run the parser.
    231   SafeBrowsingProtocolParser parser;
    232   SBChunkList chunks;
    233   bool result = parser.ParseChunk(
    234       safe_browsing_util::kMalwareList,
    235       truncated_chunks.data(),
    236       static_cast<int>(truncated_chunks.length()),
    237       &chunks);
    238   EXPECT_FALSE(result);
    239 }
    240 
    241 // Test parsing one sub chunk.
    242 TEST(SafeBrowsingProtocolParsingTest, TestSubChunk) {
    243   std::string sub_chunk("s:9:4:59\naaaaxkkkk1111\003"
    244                         "zzzz2222zzzz3333zzzz4444"
    245                         "7777\002yyyy8888yyyy9999");
    246   sub_chunk[13] = '\0';
    247 
    248   // Run the parse.
    249   SafeBrowsingProtocolParser parser;
    250   SBChunkList chunks;
    251   bool result = parser.ParseChunk(
    252       safe_browsing_util::kMalwareList,
    253       sub_chunk.data(),
    254       static_cast<int>(sub_chunk.length()),
    255       &chunks);
    256   EXPECT_TRUE(result);
    257   EXPECT_EQ(chunks.size(), 1U);
    258   EXPECT_EQ(chunks[0].chunk_number, 9);
    259   EXPECT_EQ(chunks[0].hosts.size(), 3U);
    260 
    261   EXPECT_EQ(chunks[0].hosts[0].host, 0x61616161);
    262   SBEntry* entry = chunks[0].hosts[0].entry;
    263   EXPECT_TRUE(entry->IsSub());
    264   EXPECT_TRUE(entry->IsPrefix());
    265   EXPECT_EQ(entry->chunk_id(), 0x6b6b6b6b);
    266   EXPECT_EQ(entry->prefix_count(), 0);
    267 
    268   EXPECT_EQ(chunks[0].hosts[1].host, 0x31313131);
    269   entry = chunks[0].hosts[1].entry;
    270   EXPECT_TRUE(entry->IsSub());
    271   EXPECT_TRUE(entry->IsPrefix());
    272   EXPECT_EQ(entry->prefix_count(), 3);
    273   EXPECT_EQ(entry->ChunkIdAtPrefix(0), 0x7a7a7a7a);
    274   EXPECT_EQ(entry->PrefixAt(0), 0x32323232);
    275   EXPECT_EQ(entry->ChunkIdAtPrefix(1), 0x7a7a7a7a);
    276   EXPECT_EQ(entry->PrefixAt(1), 0x33333333);
    277   EXPECT_EQ(entry->ChunkIdAtPrefix(2), 0x7a7a7a7a);
    278   EXPECT_EQ(entry->PrefixAt(2), 0x34343434);
    279 
    280   EXPECT_EQ(chunks[0].hosts[2].host, 0x37373737);
    281   entry = chunks[0].hosts[2].entry;
    282   EXPECT_TRUE(entry->IsSub());
    283   EXPECT_TRUE(entry->IsPrefix());
    284   EXPECT_EQ(entry->prefix_count(), 2);
    285   EXPECT_EQ(entry->ChunkIdAtPrefix(0), 0x79797979);
    286   EXPECT_EQ(entry->PrefixAt(0), 0x38383838);
    287   EXPECT_EQ(entry->ChunkIdAtPrefix(1), 0x79797979);
    288   EXPECT_EQ(entry->PrefixAt(1), 0x39393939);
    289 }
    290 
    291 // Test parsing one sub chunk with full hashes.
    292 TEST(SafeBrowsingProtocolParsingTest, TestSubFullChunk) {
    293   std::string sub_chunk("s:1:32:77\naaaa");
    294   sub_chunk.push_back(2);
    295 
    296   SBFullHash full_hash1, full_hash2;
    297   for (int i = 0; i < 32; ++i) {
    298     full_hash1.full_hash[i] = i % 2 ? 1 : 2;
    299     full_hash2.full_hash[i] = i % 2 ? 3 : 4;
    300   }
    301 
    302   sub_chunk.append("yyyy");
    303   sub_chunk.append(full_hash1.full_hash, 32);
    304   sub_chunk.append("zzzz");
    305   sub_chunk.append(full_hash2.full_hash, 32);
    306 
    307   // Run the parse.
    308   SafeBrowsingProtocolParser parser;
    309   SBChunkList chunks;
    310   bool result = parser.ParseChunk(
    311       safe_browsing_util::kMalwareList,
    312       sub_chunk.data(),
    313       static_cast<int>(sub_chunk.length()),
    314       &chunks);
    315   EXPECT_TRUE(result);
    316   EXPECT_EQ(chunks.size(), 1U);
    317   EXPECT_EQ(chunks[0].chunk_number, 1);
    318   EXPECT_EQ(chunks[0].hosts.size(), 1U);
    319 
    320   EXPECT_EQ(chunks[0].hosts[0].host, 0x61616161);
    321   SBEntry* entry = chunks[0].hosts[0].entry;
    322   EXPECT_TRUE(entry->IsSub());
    323   EXPECT_FALSE(entry->IsPrefix());
    324   EXPECT_EQ(entry->prefix_count(), 2);
    325   EXPECT_EQ(entry->ChunkIdAtPrefix(0), 0x79797979);
    326   EXPECT_TRUE(entry->FullHashAt(0) == full_hash1);
    327   EXPECT_EQ(entry->ChunkIdAtPrefix(1), 0x7a7a7a7a);
    328   EXPECT_TRUE(entry->FullHashAt(1) == full_hash2);
    329 }
    330 
    331 // Test parsing the SafeBrowsing update response.
    332 TEST(SafeBrowsingProtocolParsingTest, TestChunkDelete) {
    333   std::string add_del("n:1700\ni:phishy\nad:1-7,43-597,44444,99999\n"
    334                       "i:malware\nsd:21-27,42,171717\n");
    335 
    336   SafeBrowsingProtocolParser parser;
    337   int next_query_sec = 0;
    338   bool reset = false;
    339   std::vector<SBChunkDelete> deletes;
    340   std::vector<ChunkUrl> urls;
    341   EXPECT_TRUE(parser.ParseUpdate(add_del.data(),
    342                                  static_cast<int>(add_del.length()),
    343                                  &next_query_sec, &reset, &deletes, &urls));
    344 
    345   EXPECT_TRUE(urls.empty());
    346   EXPECT_FALSE(reset);
    347   EXPECT_EQ(next_query_sec, 1700);
    348   EXPECT_EQ(deletes.size(), 2U);
    349 
    350   EXPECT_EQ(deletes[0].chunk_del.size(), 4U);
    351   EXPECT_TRUE(deletes[0].chunk_del[0] == ChunkRange(1, 7));
    352   EXPECT_TRUE(deletes[0].chunk_del[1] == ChunkRange(43, 597));
    353   EXPECT_TRUE(deletes[0].chunk_del[2] == ChunkRange(44444));
    354   EXPECT_TRUE(deletes[0].chunk_del[3] == ChunkRange(99999));
    355 
    356   EXPECT_EQ(deletes[1].chunk_del.size(), 3U);
    357   EXPECT_TRUE(deletes[1].chunk_del[0] == ChunkRange(21, 27));
    358   EXPECT_TRUE(deletes[1].chunk_del[1] == ChunkRange(42));
    359   EXPECT_TRUE(deletes[1].chunk_del[2] == ChunkRange(171717));
    360 
    361   // An update response with missing list name.
    362 
    363   next_query_sec = 0;
    364   deletes.clear();
    365   urls.clear();
    366   add_del = "n:1700\nad:1-7,43-597,44444,99999\ni:malware\nsd:4,21-27171717\n";
    367   EXPECT_FALSE(parser.ParseUpdate(add_del.data(),
    368                                   static_cast<int>(add_del.length()),
    369                                   &next_query_sec, &reset, &deletes, &urls));
    370 }
    371 
    372 // Test parsing the SafeBrowsing update response.
    373 TEST(SafeBrowsingProtocolParsingTest, TestRedirects) {
    374   std::string redirects("i:goog-malware-shavar\n"
    375     "u:cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_1\n"
    376     "u:cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_2\n"
    377     "u:cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_3\n"
    378     "u:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_a_8641-8800:8641-8689,"
    379     "8691-8731,8733-8786\n");
    380 
    381   SafeBrowsingProtocolParser parser;
    382   int next_query_sec = 0;
    383   bool reset = false;
    384   std::vector<SBChunkDelete> deletes;
    385   std::vector<ChunkUrl> urls;
    386   EXPECT_TRUE(parser.ParseUpdate(redirects.data(),
    387                                  static_cast<int>(redirects.length()),
    388                                  &next_query_sec, &reset, &deletes, &urls));
    389 
    390   EXPECT_FALSE(reset);
    391   EXPECT_EQ(urls.size(), 4U);
    392   EXPECT_EQ(urls[0].url,
    393       "cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_1");
    394   EXPECT_EQ(urls[1].url,
    395       "cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_2");
    396   EXPECT_EQ(urls[2].url,
    397       "cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_3");
    398   EXPECT_EQ(urls[3].url,
    399       "s.ytimg.com/safebrowsing/rd/goog-phish-shavar_a_8641-8800:8641-8689,"
    400       "8691-8731,8733-8786");
    401   EXPECT_EQ(next_query_sec, 0);
    402   EXPECT_TRUE(deletes.empty());
    403 }
    404 
    405 // Test parsing various SafeBrowsing protocol headers.
    406 TEST(SafeBrowsingProtocolParsingTest, TestNextQueryTime) {
    407   std::string headers("n:1800\ni:goog-white-shavar\n");
    408   SafeBrowsingProtocolParser parser;
    409   int next_query_sec = 0;
    410   bool reset = false;
    411   std::vector<SBChunkDelete> deletes;
    412   std::vector<ChunkUrl> urls;
    413   EXPECT_TRUE(parser.ParseUpdate(headers.data(),
    414                                  static_cast<int>(headers.length()),
    415                                  &next_query_sec, &reset, &deletes, &urls));
    416 
    417   EXPECT_EQ(next_query_sec, 1800);
    418   EXPECT_FALSE(reset);
    419   EXPECT_TRUE(deletes.empty());
    420   EXPECT_TRUE(urls.empty());
    421 }
    422 
    423 // Test parsing data from a GetHashRequest
    424 TEST(SafeBrowsingProtocolParsingTest, TestGetHash) {
    425   std::string get_hash("goog-phish-shavar:19:96\n"
    426                        "00112233445566778899aabbccddeeff"
    427                        "00001111222233334444555566667777"
    428                        "ffffeeeeddddccccbbbbaaaa99998888");
    429   std::vector<SBFullHashResult> full_hashes;
    430   SafeBrowsingProtocolParser parser;
    431   EXPECT_TRUE(parser.ParseGetHash(get_hash.data(),
    432                                   static_cast<int>(get_hash.length()),
    433                                   &full_hashes));
    434 
    435   EXPECT_EQ(full_hashes.size(), 3U);
    436   EXPECT_EQ(memcmp(&full_hashes[0].hash,
    437                    "00112233445566778899aabbccddeeff",
    438                    sizeof(SBFullHash)), 0);
    439   EXPECT_EQ(full_hashes[0].list_name, "goog-phish-shavar");
    440   EXPECT_EQ(memcmp(&full_hashes[1].hash,
    441                    "00001111222233334444555566667777",
    442                    sizeof(SBFullHash)), 0);
    443   EXPECT_EQ(full_hashes[1].list_name, "goog-phish-shavar");
    444   EXPECT_EQ(memcmp(&full_hashes[2].hash,
    445                    "ffffeeeeddddccccbbbbaaaa99998888",
    446                    sizeof(SBFullHash)), 0);
    447   EXPECT_EQ(full_hashes[2].list_name, "goog-phish-shavar");
    448 
    449   // Test multiple lists in the GetHash results.
    450   std::string get_hash2("goog-phish-shavar:19:32\n"
    451                         "00112233445566778899aabbccddeeff"
    452                         "goog-malware-shavar:19:64\n"
    453                         "cafebeefcafebeefdeaddeaddeaddead"
    454                         "zzzzyyyyxxxxwwwwvvvvuuuuttttssss");
    455   EXPECT_TRUE(parser.ParseGetHash(get_hash2.data(),
    456                                   static_cast<int>(get_hash2.length()),
    457                                   &full_hashes));
    458 
    459   EXPECT_EQ(full_hashes.size(), 3U);
    460   EXPECT_EQ(memcmp(&full_hashes[0].hash,
    461                    "00112233445566778899aabbccddeeff",
    462                    sizeof(SBFullHash)), 0);
    463   EXPECT_EQ(full_hashes[0].list_name, "goog-phish-shavar");
    464   EXPECT_EQ(memcmp(&full_hashes[1].hash,
    465                    "cafebeefcafebeefdeaddeaddeaddead",
    466                    sizeof(SBFullHash)), 0);
    467   EXPECT_EQ(full_hashes[1].list_name, "goog-malware-shavar");
    468   EXPECT_EQ(memcmp(&full_hashes[2].hash,
    469                    "zzzzyyyyxxxxwwwwvvvvuuuuttttssss",
    470                    sizeof(SBFullHash)), 0);
    471   EXPECT_EQ(full_hashes[2].list_name, "goog-malware-shavar");
    472 }
    473 
    474 TEST(SafeBrowsingProtocolParsingTest, TestGetHashWithUnknownList) {
    475   std::string hash_response = "goog-phish-shavar:1:32\n"
    476                               "12345678901234567890123456789012"
    477                               "googpub-phish-shavar:19:32\n"
    478                               "09876543210987654321098765432109";
    479   std::vector<SBFullHashResult> full_hashes;
    480   SafeBrowsingProtocolParser parser;
    481   EXPECT_TRUE(parser.ParseGetHash(hash_response.data(),
    482                                   hash_response.size(),
    483                                   &full_hashes));
    484 
    485   EXPECT_EQ(full_hashes.size(), 1U);
    486   EXPECT_EQ(memcmp("12345678901234567890123456789012",
    487                    &full_hashes[0].hash, sizeof(SBFullHash)), 0);
    488   EXPECT_EQ(full_hashes[0].list_name, "goog-phish-shavar");
    489   EXPECT_EQ(full_hashes[0].add_chunk_id, 1);
    490 
    491   hash_response += "goog-malware-shavar:7:32\n"
    492                    "abcdefghijklmnopqrstuvwxyz123457";
    493   full_hashes.clear();
    494   EXPECT_TRUE(parser.ParseGetHash(hash_response.data(),
    495                                   hash_response.size(),
    496                                   &full_hashes));
    497 
    498   EXPECT_EQ(full_hashes.size(), 2U);
    499   EXPECT_EQ(memcmp("12345678901234567890123456789012",
    500                    &full_hashes[0].hash, sizeof(SBFullHash)), 0);
    501   EXPECT_EQ(full_hashes[0].list_name, "goog-phish-shavar");
    502   EXPECT_EQ(full_hashes[0].add_chunk_id, 1);
    503   EXPECT_EQ(memcmp("abcdefghijklmnopqrstuvwxyz123457",
    504                    &full_hashes[1].hash, sizeof(SBFullHash)), 0);
    505   EXPECT_EQ(full_hashes[1].list_name, "goog-malware-shavar");
    506   EXPECT_EQ(full_hashes[1].add_chunk_id, 7);
    507 }
    508 
    509 TEST(SafeBrowsingProtocolParsingTest, TestFormatHash) {
    510   SafeBrowsingProtocolParser parser;
    511   std::vector<SBPrefix> prefixes;
    512   std::string get_hash;
    513 
    514   prefixes.push_back(0x34333231);
    515   prefixes.push_back(0x64636261);
    516   prefixes.push_back(0x73727170);
    517 
    518   parser.FormatGetHash(prefixes, &get_hash);
    519   EXPECT_EQ(get_hash, "4:12\n1234abcdpqrs");
    520 }
    521 
    522 TEST(SafeBrowsingProtocolParsingTest, TestReset) {
    523   SafeBrowsingProtocolParser parser;
    524   std::string update("n:1800\ni:phishy\nr:pleasereset\n");
    525 
    526   bool reset = false;
    527   int next_update = -1;
    528   std::vector<SBChunkDelete> deletes;
    529   std::vector<ChunkUrl> urls;
    530   EXPECT_TRUE(parser.ParseUpdate(update.data(),
    531                                  static_cast<int>(update.size()),
    532                                  &next_update, &reset, &deletes, &urls));
    533   EXPECT_TRUE(reset);
    534 }
    535 
    536 // The SafeBrowsing service will occasionally send zero length chunks so that
    537 // client requests will have longer contiguous chunk number ranges, and thus
    538 // reduce the request size.
    539 TEST(SafeBrowsingProtocolParsingTest, TestZeroSizeAddChunk) {
    540   std::string add_chunk("a:1:4:0\n");
    541   SafeBrowsingProtocolParser parser;
    542   SBChunkList chunks;
    543 
    544   bool result = parser.ParseChunk(
    545       safe_browsing_util::kMalwareList,
    546       add_chunk.data(),
    547       static_cast<int>(add_chunk.length()),
    548       &chunks);
    549   EXPECT_TRUE(result);
    550   EXPECT_EQ(chunks.size(), 1U);
    551   EXPECT_EQ(chunks[0].chunk_number, 1);
    552   EXPECT_EQ(chunks[0].hosts.size(), 0U);
    553 
    554   // Now test a zero size chunk in between normal chunks.
    555   chunks.clear();
    556   std::string add_chunks("a:1:4:18\n1234\001abcd5678\001wxyz"
    557                          "a:2:4:0\n"
    558                          "a:3:4:9\ncafe\001beef");
    559   result = parser.ParseChunk(
    560       safe_browsing_util::kMalwareList,
    561       add_chunks.data(),
    562       static_cast<int>(add_chunks.length()),
    563       &chunks);
    564   EXPECT_TRUE(result);
    565   EXPECT_EQ(chunks.size(), 3U);
    566 
    567   // See that each chunk has the right content.
    568   EXPECT_EQ(chunks[0].chunk_number, 1);
    569   EXPECT_EQ(chunks[0].hosts.size(), 2U);
    570   EXPECT_EQ(chunks[0].hosts[0].host, 0x34333231);
    571   EXPECT_EQ(chunks[0].hosts[0].entry->PrefixAt(0), 0x64636261);
    572   EXPECT_EQ(chunks[0].hosts[1].host, 0x38373635);
    573   EXPECT_EQ(chunks[0].hosts[1].entry->PrefixAt(0), 0x7a797877);
    574 
    575   EXPECT_EQ(chunks[1].chunk_number, 2);
    576   EXPECT_EQ(chunks[1].hosts.size(), 0U);
    577 
    578   EXPECT_EQ(chunks[2].chunk_number, 3);
    579   EXPECT_EQ(chunks[2].hosts.size(), 1U);
    580   EXPECT_EQ(chunks[2].hosts[0].host, 0x65666163);
    581   EXPECT_EQ(chunks[2].hosts[0].entry->PrefixAt(0), 0x66656562);
    582 }
    583 
    584 // Test parsing a zero sized sub chunk.
    585 TEST(SafeBrowsingProtocolParsingTest, TestZeroSizeSubChunk) {
    586   std::string sub_chunk("s:9:4:0\n");
    587   SafeBrowsingProtocolParser parser;
    588   SBChunkList chunks;
    589 
    590   bool result = parser.ParseChunk(
    591       safe_browsing_util::kMalwareList,
    592       sub_chunk.data(),
    593       static_cast<int>(sub_chunk.length()),
    594       &chunks);
    595   EXPECT_TRUE(result);
    596   EXPECT_EQ(chunks.size(), 1U);
    597   EXPECT_EQ(chunks[0].chunk_number, 9);
    598   EXPECT_EQ(chunks[0].hosts.size(), 0U);
    599   chunks.clear();
    600 
    601   // Test parsing a zero sized sub chunk mixed in with content carrying chunks.
    602   std::string sub_chunks("s:1:4:9\nabcdxwxyz"
    603                          "s:2:4:0\n"
    604                          "s:3:4:26\nefgh\0011234pqrscafe\0015678lmno");
    605   sub_chunks[12] = '\0';
    606 
    607   result = parser.ParseChunk(
    608       safe_browsing_util::kMalwareList,
    609       sub_chunks.data(),
    610       static_cast<int>(sub_chunks.length()),
    611       &chunks);
    612   EXPECT_TRUE(result);
    613 
    614   EXPECT_EQ(chunks[0].chunk_number, 1);
    615   EXPECT_EQ(chunks[0].hosts.size(), 1U);
    616   EXPECT_EQ(chunks[0].hosts[0].host, 0x64636261);
    617   EXPECT_EQ(chunks[0].hosts[0].entry->prefix_count(), 0);
    618 
    619   EXPECT_EQ(chunks[1].chunk_number, 2);
    620   EXPECT_EQ(chunks[1].hosts.size(), 0U);
    621 
    622   EXPECT_EQ(chunks[2].chunk_number, 3);
    623   EXPECT_EQ(chunks[2].hosts.size(), 2U);
    624   EXPECT_EQ(chunks[2].hosts[0].host, 0x68676665);
    625   EXPECT_EQ(chunks[2].hosts[0].entry->prefix_count(), 1);
    626   EXPECT_EQ(chunks[2].hosts[0].entry->PrefixAt(0), 0x73727170);
    627   EXPECT_EQ(chunks[2].hosts[0].entry->ChunkIdAtPrefix(0), 0x31323334);
    628   EXPECT_EQ(chunks[2].hosts[1].host, 0x65666163);
    629   EXPECT_EQ(chunks[2].hosts[1].entry->prefix_count(), 1);
    630   EXPECT_EQ(chunks[2].hosts[1].entry->PrefixAt(0), 0x6f6e6d6c);
    631   EXPECT_EQ(chunks[2].hosts[1].entry->ChunkIdAtPrefix(0), 0x35363738);
    632 }
    633 
    634 TEST(SafeBrowsingProtocolParsingTest, TestAddBinHashChunks) {
    635   std::string add_chunk("a:1:4:16\naaaabbbbccccdddd"
    636                         "a:2:4:8\n11112222");
    637   // Run the parse.
    638   SafeBrowsingProtocolParser parser;
    639   SBChunkList chunks;
    640   bool result = parser.ParseChunk(
    641       safe_browsing_util::kBinHashList,
    642       add_chunk.data(),
    643       static_cast<int>(add_chunk.length()),
    644       &chunks);
    645   EXPECT_TRUE(result);
    646   EXPECT_EQ(chunks.size(), 2U);
    647   EXPECT_EQ(chunks[0].chunk_number, 1);
    648   EXPECT_EQ(chunks[0].hosts.size(), 1U);
    649 
    650   EXPECT_EQ(chunks[0].hosts[0].host, 0);
    651   SBEntry* entry = chunks[0].hosts[0].entry;
    652   EXPECT_TRUE(entry->IsAdd());
    653   EXPECT_TRUE(entry->IsPrefix());
    654   EXPECT_EQ(entry->prefix_count(), 4);
    655 
    656   EXPECT_EQ(chunks[1].chunk_number, 2);
    657   EXPECT_EQ(chunks[1].hosts.size(), 1U);
    658 
    659   EXPECT_EQ(chunks[1].hosts[0].host, 0);
    660   entry = chunks[1].hosts[0].entry;
    661   EXPECT_TRUE(entry->IsAdd());
    662   EXPECT_TRUE(entry->IsPrefix());
    663   EXPECT_EQ(entry->prefix_count(), 2);
    664   EXPECT_EQ(entry->PrefixAt(0), 0x31313131);
    665   EXPECT_EQ(entry->PrefixAt(1), 0x32323232);
    666 }
    667 
    668 // Test parsing one add chunk where a hostkey spans several entries.
    669 TEST(SafeBrowsingProtocolParsingTest, TestAddBigBinHashChunk) {
    670   std::string add_chunk("a:1:4:1028\n");
    671   for (int i = 0; i < 257; ++i)
    672     add_chunk.append(base::StringPrintf("%04d", i));
    673 
    674   SafeBrowsingProtocolParser parser;
    675   SBChunkList chunks;
    676   bool result = parser.ParseChunk(
    677       safe_browsing_util::kBinHashList,
    678       add_chunk.data(),
    679       static_cast<int>(add_chunk.length()),
    680       &chunks);
    681   EXPECT_TRUE(result);
    682   EXPECT_EQ(chunks.size(), 1U);
    683   EXPECT_EQ(chunks[0].chunk_number, 1);
    684 
    685   EXPECT_EQ(chunks[0].hosts.size(), 1U);
    686 
    687   const SBChunkHost& host0 = chunks[0].hosts[0];
    688   EXPECT_EQ(host0.host, 0);
    689   EXPECT_EQ(host0.entry->prefix_count(), 257);
    690 }
    691 
    692 // Test parsing one sub chunk.
    693 TEST(SafeBrowsingProtocolParsingTest, TestSubBinHashChunk) {
    694   std::string sub_chunk("s:9:4:16\n1111mmmm2222nnnn");
    695 
    696   // Run the parser.
    697   SafeBrowsingProtocolParser parser;
    698   SBChunkList chunks;
    699   bool result = parser.ParseChunk(
    700       safe_browsing_util::kBinHashList,
    701       sub_chunk.data(),
    702       static_cast<int>(sub_chunk.length()),
    703       &chunks);
    704   EXPECT_TRUE(result);
    705   EXPECT_EQ(chunks.size(), 1U);
    706   EXPECT_EQ(chunks[0].chunk_number, 9);
    707   EXPECT_EQ(chunks[0].hosts.size(), 1U);
    708 
    709   EXPECT_EQ(chunks[0].hosts[0].host, 0);
    710   SBEntry* entry = chunks[0].hosts[0].entry;
    711   EXPECT_TRUE(entry->IsSub());
    712   EXPECT_TRUE(entry->IsPrefix());
    713   EXPECT_EQ(entry->prefix_count(), 2);
    714   EXPECT_EQ(entry->ChunkIdAtPrefix(0), 0x31313131);
    715   EXPECT_EQ(entry->PrefixAt(0), 0x6d6d6d6d);
    716   EXPECT_EQ(entry->ChunkIdAtPrefix(1), 0x32323232);
    717   EXPECT_EQ(entry->PrefixAt(1), 0x6e6e6e6e);
    718 }
    719 
    720 TEST(SafeBrowsingProtocolParsingTest, TestAddDownloadWhitelistChunk) {
    721   std::string add_chunk("a:1:32:32\nxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    722                         "a:2:32:64\nyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"
    723                         "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz");
    724   // Run the parse.
    725   SafeBrowsingProtocolParser parser;
    726   SBChunkList chunks;
    727   bool result = parser.ParseChunk(
    728       safe_browsing_util::kDownloadWhiteList,
    729       add_chunk.data(),
    730       static_cast<int>(add_chunk.length()),
    731       &chunks);
    732   EXPECT_TRUE(result);
    733   EXPECT_EQ(chunks.size(), 2U);
    734   EXPECT_EQ(chunks[0].chunk_number, 1);
    735   EXPECT_EQ(chunks[0].hosts.size(), 1U);
    736   EXPECT_EQ(chunks[0].hosts[0].host, 0);
    737   SBEntry* entry = chunks[0].hosts[0].entry;
    738   EXPECT_TRUE(entry->IsAdd());
    739   EXPECT_FALSE(entry->IsPrefix());
    740   EXPECT_EQ(entry->prefix_count(), 1);
    741   SBFullHash full;
    742   memcpy(full.full_hash, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 32);
    743   EXPECT_TRUE(entry->FullHashAt(0) == full);
    744 
    745   EXPECT_EQ(chunks[1].chunk_number, 2);
    746   EXPECT_EQ(chunks[1].hosts.size(), 1U);
    747   EXPECT_EQ(chunks[1].hosts[0].host, 0);
    748   entry = chunks[1].hosts[0].entry;
    749   EXPECT_TRUE(entry->IsAdd());
    750   EXPECT_FALSE(entry->IsPrefix());
    751   EXPECT_EQ(entry->prefix_count(), 2);
    752   memcpy(full.full_hash, "yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy", 32);
    753   EXPECT_TRUE(entry->FullHashAt(0) == full);
    754   memcpy(full.full_hash, "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz", 32);
    755   EXPECT_TRUE(entry->FullHashAt(1) == full);
    756 }
    757 
    758 // Test parsing one sub chunk.
    759 TEST(SafeBrowsingProtocolParsingTest, TestSubDownloadWhitelistChunk) {
    760   std::string sub_chunk("s:1:32:36\n1111xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx");
    761 
    762   // Run the parser.
    763   SafeBrowsingProtocolParser parser;
    764   SBChunkList chunks;
    765   bool result = parser.ParseChunk(
    766       safe_browsing_util::kDownloadWhiteList,
    767       sub_chunk.data(),
    768       static_cast<int>(sub_chunk.length()),
    769       &chunks);
    770   ASSERT_TRUE(result);
    771   ASSERT_EQ(chunks.size(), 1U);
    772   EXPECT_EQ(chunks[0].chunk_number, 1);
    773   EXPECT_EQ(chunks[0].hosts.size(), 1U);
    774 
    775   EXPECT_EQ(chunks[0].hosts[0].host, 0);
    776   SBEntry* entry = chunks[0].hosts[0].entry;
    777   EXPECT_TRUE(entry->IsSub());
    778   ASSERT_FALSE(entry->IsPrefix());
    779   ASSERT_EQ(entry->prefix_count(), 1);
    780   EXPECT_EQ(entry->ChunkIdAtPrefix(0), 0x31313131);
    781   SBFullHash full;
    782   memcpy(full.full_hash, "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 32);
    783   EXPECT_TRUE(entry->FullHashAt(0) == full);
    784 }
    785