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 #include <string>
      6 
      7 #include "base/strings/stringprintf.h"
      8 #include "base/time/time.h"
      9 #include "chrome/browser/safe_browsing/protocol_parser.h"
     10 #include "chrome/browser/safe_browsing/safe_browsing_util.h"
     11 #include "testing/gtest/include/gtest/gtest.h"
     12 
     13 namespace {
     14 
     15 #if defined(OS_ANDROID)
     16 const char kDefaultPhishList[] = "goog-mobilephish-shavar";
     17 const char kDefaultMalwareList[] = "goog-mobilemalware-shavar";
     18 #else
     19 const char kDefaultPhishList[] = "goog-phish-shavar";
     20 const char kDefaultMalwareList[] = "goog-malware-shavar";
     21 #endif
     22 
     23 // Test parsing one add chunk.
     24 TEST(SafeBrowsingProtocolParsingTest, TestAddChunk) {
     25   const char kRawAddChunk[] = {
     26     '\0', '\0', '\0', '\x1C',  // 32-bit payload length in network byte order.
     27     '\x08',                    // field 1, wire format varint
     28     '\x01',                    // chunk_number varint 1
     29     '\x22',                    // field 4, wire format length-delimited
     30     '\x18',                    // varint length 24
     31     '1', '1', '1', '1',        // 4-byte prefixes
     32     '2', '2', '2', '2',
     33     '3', '3', '3', '3',
     34     '4', '4', '4', '4',
     35     '8', '8', '8', '8',
     36     '9', '9', '9', '9',
     37   };
     38 
     39   ScopedVector<SBChunkData> chunks;
     40   EXPECT_TRUE(safe_browsing::ParseChunk(kRawAddChunk, sizeof(kRawAddChunk),
     41                                         &chunks));
     42   ASSERT_EQ(1U, chunks.size());
     43   EXPECT_EQ(1, chunks[0]->ChunkNumber());
     44   EXPECT_TRUE(chunks[0]->IsAdd());
     45   EXPECT_FALSE(chunks[0]->IsSub());
     46   EXPECT_TRUE(chunks[0]->IsPrefix());
     47   EXPECT_FALSE(chunks[0]->IsFullHash());
     48   ASSERT_EQ(6U, chunks[0]->PrefixCount());
     49   EXPECT_EQ(0x31313131U, chunks[0]->PrefixAt(0));  // 1111
     50   EXPECT_EQ(0x32323232U, chunks[0]->PrefixAt(1));  // 2222
     51   EXPECT_EQ(0x33333333U, chunks[0]->PrefixAt(2));  // 3333
     52   EXPECT_EQ(0x34343434U, chunks[0]->PrefixAt(3));  // 4444
     53   EXPECT_EQ(0x38383838U, chunks[0]->PrefixAt(4));  // 8888
     54   EXPECT_EQ(0x39393939U, chunks[0]->PrefixAt(5));  // 9999
     55 }
     56 
     57 // Test parsing one add chunk with full hashes.
     58 TEST(SafeBrowsingProtocolParsingTest, TestAddFullChunk) {
     59   const char kRawAddChunk[] = {
     60     '\0', '\0', '\0', '\x46',  // 32-bit payload length in network byte order.
     61     '\x08',                    // field 1, wire format varint
     62     '\x01',                    // chunk_number varint 1
     63     '\x18',                    // field 3, wire format varint
     64     '\x01',                    // enum PrefixType == FULL_32B
     65     '\x22',                    // field 4, wire format length-delimited
     66     '\x40',                    // varint length 64 (2 full hashes)
     67 
     68     '0', '1', '0', '1', '0', '1', '0', '1',
     69     '0', '1', '0', '1', '0', '1', '0', '1',
     70     '0', '1', '0', '1', '0', '1', '0', '1',
     71     '0', '1', '0', '1', '0', '1', '0', '1',
     72 
     73     '2', '3', '2', '3', '2', '3', '2', '3',
     74     '2', '3', '2', '3', '2', '3', '2', '3',
     75     '2', '3', '2', '3', '2', '3', '2', '3',
     76     '2', '3', '2', '3', '2', '3', '2', '3',
     77   };
     78 
     79   SBFullHash full_hash1, full_hash2;
     80   for (int i = 0; i < 32; ++i) {
     81     full_hash1.full_hash[i] = i % 2 ? '1' : '0';
     82     full_hash2.full_hash[i] = i % 2 ? '3' : '2';
     83   }
     84 
     85   ScopedVector<SBChunkData> chunks;
     86   EXPECT_TRUE(safe_browsing::ParseChunk(kRawAddChunk, sizeof(kRawAddChunk),
     87                                         &chunks));
     88   ASSERT_EQ(1U, chunks.size());
     89   EXPECT_EQ(1, chunks[0]->ChunkNumber());
     90   EXPECT_TRUE(chunks[0]->IsAdd());
     91   EXPECT_FALSE(chunks[0]->IsSub());
     92   EXPECT_FALSE(chunks[0]->IsPrefix());
     93   EXPECT_TRUE(chunks[0]->IsFullHash());
     94 
     95   ASSERT_EQ(2U, chunks[0]->FullHashCount());
     96   EXPECT_TRUE(SBFullHashEqual(chunks[0]->FullHashAt(0), full_hash1));
     97   EXPECT_TRUE(SBFullHashEqual(chunks[0]->FullHashAt(1), full_hash2));
     98 }
     99 
    100 // Test parsing multiple add chunks. We'll use the same chunk as above, and add
    101 // one more after it.
    102 TEST(SafeBrowsingProtocolParsingTest, TestAddChunks) {
    103   const char kRawAddChunk[] = {
    104     '\0', '\0', '\0', '\x1C',  // 32-bit payload length in network byte order.
    105     '\x08',                    // field 1, wire format varint
    106     '\x01',                    // chunk_number varint 1
    107     '\x22',                    // field 4, wire format length-delimited
    108     '\x18',                    // varint length 24
    109 
    110     '1', '1', '1', '1',        // 4-byte prefixes
    111     '2', '2', '2', '2',
    112     '3', '3', '3', '3',
    113     '4', '4', '4', '4',
    114     '8', '8', '8', '8',
    115     '9', '9', '9', '9',
    116 
    117     '\0', '\0', '\0', '\x0C',  // 32-bit payload length in network byte order.
    118     '\x08',                    // field 1, wire format varint
    119     '\x02',                    // chunk_number varint 1
    120     '\x22',                    // field 4, wire format length-delimited
    121     '\x08',                    // varint length 8
    122     'p', 'p', 'p', 'p',        // 4-byte prefixes
    123     'g', 'g', 'g', 'g',
    124   };
    125 
    126   ScopedVector<SBChunkData> chunks;
    127   EXPECT_TRUE(safe_browsing::ParseChunk(kRawAddChunk, sizeof(kRawAddChunk),
    128                                         &chunks));
    129   ASSERT_EQ(2U, chunks.size());
    130 
    131   EXPECT_EQ(1, chunks[0]->ChunkNumber());
    132   EXPECT_TRUE(chunks[0]->IsAdd());
    133   EXPECT_FALSE(chunks[0]->IsSub());
    134   EXPECT_TRUE(chunks[0]->IsPrefix());
    135   EXPECT_FALSE(chunks[0]->IsFullHash());
    136   ASSERT_EQ(6U, chunks[0]->PrefixCount());
    137   EXPECT_EQ(0x31313131U, chunks[0]->PrefixAt(0));  // 1111
    138   EXPECT_EQ(0x32323232U, chunks[0]->PrefixAt(1));  // 2222
    139   EXPECT_EQ(0x33333333U, chunks[0]->PrefixAt(2));  // 3333
    140   EXPECT_EQ(0x34343434U, chunks[0]->PrefixAt(3));  // 4444
    141   EXPECT_EQ(0x38383838U, chunks[0]->PrefixAt(4));  // 8888
    142   EXPECT_EQ(0x39393939U, chunks[0]->PrefixAt(5));  // 9999
    143 
    144   EXPECT_EQ(2, chunks[1]->ChunkNumber());
    145   EXPECT_TRUE(chunks[1]->IsAdd());
    146   EXPECT_FALSE(chunks[1]->IsSub());
    147   EXPECT_TRUE(chunks[1]->IsPrefix());
    148   EXPECT_FALSE(chunks[1]->IsFullHash());
    149   ASSERT_EQ(2U, chunks[1]->PrefixCount());
    150   EXPECT_EQ(0x70707070U, chunks[1]->PrefixAt(0));  // pppp
    151   EXPECT_EQ(0x67676767U, chunks[1]->PrefixAt(1));  // gggg
    152 }
    153 
    154 TEST(SafeBrowsingProtocolParsingTest, TestTruncatedPrefixChunk) {
    155   // This chunk delares there are 6 prefixes but actually only contains 3.
    156   const char kRawAddChunk[] = {
    157     '\0', '\0', '\0', '\x1C',  // 32-bit payload length in network byte order.
    158     '\x08',                    // field 1, wire format varint
    159     '\x01',                    // chunk_number varint 1
    160     '\x22',                    // field 4, wire format length-delimited
    161     '\x18',                    // varint length 24
    162     '1', '1', '1', '1',        // 4-byte prefixes
    163     '2', '2', '2', '2',
    164     '3', '3', '3', '3',
    165   };
    166 
    167   ScopedVector<SBChunkData> chunks;
    168   EXPECT_FALSE(safe_browsing::ParseChunk(kRawAddChunk, sizeof(kRawAddChunk),
    169                                          &chunks));
    170 }
    171 
    172 TEST(SafeBrowsingProtocolParsingTest, TestTruncatedFullHashChunk) {
    173   // This chunk delares there are two full hashes but there is only one.
    174   const char kRawAddChunk[] = {
    175     '\0', '\0', '\0', '\x46',  // 32-bit payload length in network byte order.
    176     '\x08',                    // field 1, wire format varint
    177     '\x01',                    // chunk_number varint 1
    178     '\x18',                    // field 3, wire format varint
    179     '\x01',                    // enum PrefixType == FULL_32B
    180     '\x22',                    // field 4, wire format length-delimited
    181     '\x40',                    // varint length 64 (2 full hashes)
    182 
    183     '0', '1', '0', '1', '0', '1', '0', '1',
    184     '0', '1', '0', '1', '0', '1', '0', '1',
    185     '0', '1', '0', '1', '0', '1', '0', '1',
    186     '0', '1', '0', '1', '0', '1', '0', '1',
    187   };
    188 
    189   ScopedVector<SBChunkData> chunks;
    190   EXPECT_FALSE(safe_browsing::ParseChunk(kRawAddChunk, sizeof(kRawAddChunk),
    191                                          &chunks));
    192 }
    193 
    194 TEST(SafeBrowsingProtocolParsingTest, TestHugeChunk) {
    195   // This chunk delares there are 6 prefixes but actually only contains 3.
    196   const char kRawAddChunk[] = {
    197     '\x1', '\0', '\0', '\0',   // 32-bit payload length in network byte order.
    198     '\x08',                    // field 1, wire format varint
    199     '\x01',                    // chunk_number varint 1
    200     '\x22',                    // field 4, wire format length-delimited
    201     '\x18',                    // varint length 24
    202     '1', '1', '1', '1',        // 4-byte prefixes
    203     '2', '2', '2', '2',
    204     '3', '3', '3', '3',
    205   };
    206 
    207   ScopedVector<SBChunkData> chunks;
    208   EXPECT_FALSE(safe_browsing::ParseChunk(kRawAddChunk, sizeof(kRawAddChunk),
    209                                          &chunks));
    210 }
    211 
    212 // Test parsing one sub chunk.
    213 TEST(SafeBrowsingProtocolParsingTest, TestSubChunk) {
    214   const char kRawSubChunk[] = {
    215     '\0', '\0', '\0', '\x12',  // 32-bit payload length in network byte order
    216     '\x08',                    // field 1, wire format varint
    217     '\x03',                    // chunk_number varint 3
    218     '\x10',                    // field 2, wire format varint
    219     '\x01',                    // enum ChunkType == SUB
    220     '\x22',                    // field 4, wire format length-delimited
    221     '\x08',                    // varint length 8 (2 prefixes)
    222     '1', '1', '1', '1',        // 4-byte prefixes
    223     '2', '2', '2', '2',
    224     '\x2a',                    // field 5, wire format length-delimited
    225     '\x02',                    // varint length 2 (2 add-chunk numbers)
    226     '\x07', '\x09',            // varint 7, varint 9
    227   };
    228 
    229   ScopedVector<SBChunkData> chunks;
    230   EXPECT_TRUE(safe_browsing::ParseChunk(kRawSubChunk, sizeof(kRawSubChunk),
    231                                         &chunks));
    232   ASSERT_EQ(1U, chunks.size());
    233   EXPECT_EQ(3, chunks[0]->ChunkNumber());
    234   EXPECT_FALSE(chunks[0]->IsAdd());
    235   EXPECT_TRUE(chunks[0]->IsSub());
    236   EXPECT_TRUE(chunks[0]->IsPrefix());
    237   EXPECT_FALSE(chunks[0]->IsFullHash());
    238   ASSERT_EQ(2U, chunks[0]->PrefixCount());
    239   EXPECT_EQ(0x31313131U, chunks[0]->PrefixAt(0));  // 1111
    240   EXPECT_EQ(7, chunks[0]->AddChunkNumberAt(0));
    241   EXPECT_EQ(0x32323232U, chunks[0]->PrefixAt(1));  // 2222
    242   EXPECT_EQ(9, chunks[0]->AddChunkNumberAt(1));
    243 }
    244 
    245 // Test parsing one sub chunk with full hashes.
    246 TEST(SafeBrowsingProtocolParsingTest, TestSubFullChunk) {
    247   const char kRawSubChunk[] = {
    248     '\0', '\0', '\0', '\x4C',  // 32-bit payload length in network byte order.
    249     '\x08',                    // field 1, wire format varint
    250     '\x02',                    // chunk_number varint 2
    251     '\x10',                    // field 2, wire format varint
    252     '\x01',                    // enum ChunkType == SUB
    253     '\x18',                    // field 3, wire format varint
    254     '\x01',                    // enum PrefixType == FULL_32B
    255     '\x22',                    // field 4, wire format length-delimited
    256     '\x40',                    // varint length 64 (2 full hashes)
    257 
    258     '0', '1', '0', '1', '0', '1', '0', '1',
    259     '0', '1', '0', '1', '0', '1', '0', '1',
    260     '0', '1', '0', '1', '0', '1', '0', '1',
    261     '0', '1', '0', '1', '0', '1', '0', '1',
    262 
    263     '2', '3', '2', '3', '2', '3', '2', '3',
    264     '2', '3', '2', '3', '2', '3', '2', '3',
    265     '2', '3', '2', '3', '2', '3', '2', '3',
    266     '2', '3', '2', '3', '2', '3', '2', '3',
    267 
    268     '\x2a',                    // field 5, wire format length-delimited
    269     '\x02',                    // varint length 2 (2 add-chunk numbers)
    270     '\x07', '\x09',            // varint 7, varint 9
    271   };
    272 
    273   SBFullHash full_hash1, full_hash2;
    274   for (int i = 0; i < 32; ++i) {
    275     full_hash1.full_hash[i] = i % 2 ? '1' : '0';
    276     full_hash2.full_hash[i] = i % 2 ? '3' : '2';
    277   }
    278 
    279   ScopedVector<SBChunkData> chunks;
    280   EXPECT_TRUE(safe_browsing::ParseChunk(kRawSubChunk, sizeof(kRawSubChunk),
    281                                         &chunks));
    282   ASSERT_EQ(1U, chunks.size());
    283   EXPECT_EQ(2, chunks[0]->ChunkNumber());
    284   EXPECT_FALSE(chunks[0]->IsAdd());
    285   EXPECT_TRUE(chunks[0]->IsSub());
    286   EXPECT_FALSE(chunks[0]->IsPrefix());
    287   EXPECT_TRUE(chunks[0]->IsFullHash());
    288 
    289   ASSERT_EQ(2U, chunks[0]->FullHashCount());
    290   EXPECT_TRUE(SBFullHashEqual(chunks[0]->FullHashAt(0), full_hash1));
    291   EXPECT_EQ(7, chunks[0]->AddChunkNumberAt(0));
    292   EXPECT_TRUE(SBFullHashEqual(chunks[0]->FullHashAt(1), full_hash2));
    293   EXPECT_EQ(9, chunks[0]->AddChunkNumberAt(1));
    294 }
    295 
    296 // Test parsing the SafeBrowsing update response.
    297 TEST(SafeBrowsingProtocolParsingTest, TestChunkDelete) {
    298   std::string add_del("n:1700\ni:phishy\nad:1-7,43-597,44444,99999\n"
    299                       "i:malware\nsd:21-27,42,171717\n");
    300 
    301   size_t next_query_sec = 0;
    302   bool reset = false;
    303   std::vector<SBChunkDelete> deletes;
    304   std::vector<ChunkUrl> urls;
    305   EXPECT_TRUE(safe_browsing::ParseUpdate(add_del.data(), add_del.length(),
    306                                          &next_query_sec, &reset,
    307                                          &deletes, &urls));
    308 
    309   EXPECT_TRUE(urls.empty());
    310   EXPECT_FALSE(reset);
    311   EXPECT_EQ(1700U, next_query_sec);
    312   ASSERT_EQ(2U, deletes.size());
    313 
    314   ASSERT_EQ(4U, deletes[0].chunk_del.size());
    315   EXPECT_TRUE(deletes[0].chunk_del[0] == ChunkRange(1, 7));
    316   EXPECT_TRUE(deletes[0].chunk_del[1] == ChunkRange(43, 597));
    317   EXPECT_TRUE(deletes[0].chunk_del[2] == ChunkRange(44444));
    318   EXPECT_TRUE(deletes[0].chunk_del[3] == ChunkRange(99999));
    319 
    320   ASSERT_EQ(3U, deletes[1].chunk_del.size());
    321   EXPECT_TRUE(deletes[1].chunk_del[0] == ChunkRange(21, 27));
    322   EXPECT_TRUE(deletes[1].chunk_del[1] == ChunkRange(42));
    323   EXPECT_TRUE(deletes[1].chunk_del[2] == ChunkRange(171717));
    324 
    325   // An update response with missing list name.
    326   next_query_sec = 0;
    327   deletes.clear();
    328   urls.clear();
    329   add_del = "n:1700\nad:1-7,43-597,44444,99999\ni:malware\nsd:4,21-27171717\n";
    330   EXPECT_FALSE(safe_browsing::ParseUpdate(add_del.data(), add_del.length(),
    331                                           &next_query_sec, &reset,
    332                                           &deletes, &urls));
    333 }
    334 
    335 // Test parsing the SafeBrowsing update response.
    336 TEST(SafeBrowsingProtocolParsingTest, TestRedirects) {
    337   const std::string redirects(base::StringPrintf(
    338       "i:%s\n"
    339       "u:cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_1\n"
    340       "u:cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_2\n"
    341       "u:cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_3\n"
    342       "u:s.ytimg.com/safebrowsing/rd/goog-phish-shavar_a_8641-8800:8641-8689,"
    343       "8691-8731,8733-8786\n",
    344       kDefaultMalwareList));
    345 
    346   size_t next_query_sec = 0;
    347   bool reset = false;
    348   std::vector<SBChunkDelete> deletes;
    349   std::vector<ChunkUrl> urls;
    350   EXPECT_TRUE(safe_browsing::ParseUpdate(redirects.data(), redirects.length(),
    351                                          &next_query_sec, &reset,
    352                                          &deletes, &urls));
    353   EXPECT_FALSE(reset);
    354   EXPECT_EQ(0U, next_query_sec);
    355   EXPECT_TRUE(deletes.empty());
    356 
    357   ASSERT_EQ(4U, urls.size());
    358   EXPECT_EQ("cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_1",
    359             urls[0].url);
    360   EXPECT_EQ("cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_2",
    361             urls[1].url);
    362   EXPECT_EQ("cache.googlevideo.com/safebrowsing/rd/goog-malware-shavar_s_3",
    363             urls[2].url);
    364   EXPECT_EQ("s.ytimg.com/safebrowsing/rd/goog-phish-shavar_a_8641-8800:"
    365             "8641-8689,8691-8731,8733-8786",
    366             urls[3].url);
    367 }
    368 
    369 // Test parsing various SafeBrowsing protocol headers.
    370 TEST(SafeBrowsingProtocolParsingTest, TestNextQueryTime) {
    371   std::string headers("n:1800\ni:goog-white-shavar\n");
    372   size_t next_query_sec = 0;
    373   bool reset = false;
    374   std::vector<SBChunkDelete> deletes;
    375   std::vector<ChunkUrl> urls;
    376   EXPECT_TRUE(safe_browsing::ParseUpdate(headers.data(), headers.length(),
    377                                          &next_query_sec, &reset,
    378                                          &deletes, &urls));
    379 
    380   EXPECT_EQ(1800U, next_query_sec);
    381   EXPECT_FALSE(reset);
    382   EXPECT_TRUE(deletes.empty());
    383   EXPECT_TRUE(urls.empty());
    384 }
    385 
    386 // Test parsing data from a GetHashRequest
    387 TEST(SafeBrowsingProtocolParsingTest, TestGetHash) {
    388   const std::string get_hash(base::StringPrintf(
    389       "45\n"
    390       "%s:32:3\n"
    391       "00112233445566778899aabbccddeeff"
    392       "00001111222233334444555566667777"
    393       "ffffeeeeddddccccbbbbaaaa99998888",
    394       kDefaultPhishList));
    395   std::vector<SBFullHashResult> full_hashes;
    396   base::TimeDelta cache_lifetime;
    397   EXPECT_TRUE(safe_browsing::ParseGetHash(get_hash.data(), get_hash.length(),
    398                                           &cache_lifetime, &full_hashes));
    399 
    400   ASSERT_EQ(3U, full_hashes.size());
    401   EXPECT_EQ(memcmp(&full_hashes[0].hash,
    402                    "00112233445566778899aabbccddeeff",
    403                    sizeof(SBFullHash)), 0);
    404   EXPECT_EQ(safe_browsing_util::PHISH, full_hashes[0].list_id);
    405   EXPECT_EQ(memcmp(&full_hashes[1].hash,
    406                    "00001111222233334444555566667777",
    407                    sizeof(SBFullHash)), 0);
    408   EXPECT_EQ(safe_browsing_util::PHISH, full_hashes[1].list_id);
    409   EXPECT_EQ(memcmp(&full_hashes[2].hash,
    410                    "ffffeeeeddddccccbbbbaaaa99998888",
    411                    sizeof(SBFullHash)), 0);
    412   EXPECT_EQ(safe_browsing_util::PHISH, full_hashes[2].list_id);
    413 
    414   // Test multiple lists in the GetHash results.
    415   const std::string get_hash2(base::StringPrintf(
    416       "45\n"
    417       "%s:32:1\n"
    418       "00112233445566778899aabbccddeeff"
    419       "%s:32:2\n"
    420       "cafebeefcafebeefdeaddeaddeaddead"
    421       "zzzzyyyyxxxxwwwwvvvvuuuuttttssss",
    422       kDefaultPhishList,
    423       kDefaultMalwareList));
    424   EXPECT_TRUE(safe_browsing::ParseGetHash(get_hash2.data(), get_hash2.length(),
    425                                           &cache_lifetime, &full_hashes));
    426 
    427   ASSERT_EQ(3U, full_hashes.size());
    428   EXPECT_EQ(memcmp(&full_hashes[0].hash,
    429                    "00112233445566778899aabbccddeeff",
    430                    sizeof(SBFullHash)), 0);
    431   EXPECT_EQ(safe_browsing_util::PHISH, full_hashes[0].list_id);
    432   EXPECT_EQ(memcmp(&full_hashes[1].hash,
    433                    "cafebeefcafebeefdeaddeaddeaddead",
    434                    sizeof(SBFullHash)), 0);
    435   EXPECT_EQ(safe_browsing_util::MALWARE, full_hashes[1].list_id);
    436   EXPECT_EQ(memcmp(&full_hashes[2].hash,
    437                    "zzzzyyyyxxxxwwwwvvvvuuuuttttssss",
    438                    sizeof(SBFullHash)), 0);
    439   EXPECT_EQ(safe_browsing_util::MALWARE, full_hashes[2].list_id);
    440 
    441   // Test metadata parsing.
    442   const std::string get_hash3(base::StringPrintf(
    443       "45\n"
    444       "%s:32:2:m\n"
    445       "zzzzyyyyxxxxwwwwvvvvuuuuttttssss"
    446       "00112233445566778899aabbccddeeff"
    447       "2\nab2\nxy"
    448       "%s:32:1\n"
    449       "cafebeefcafebeefdeaddeaddeaddead",
    450       kDefaultMalwareList,
    451       kDefaultPhishList));
    452   EXPECT_TRUE(safe_browsing::ParseGetHash(get_hash3.data(), get_hash3.length(),
    453                                           &cache_lifetime, &full_hashes));
    454 
    455   ASSERT_EQ(3U, full_hashes.size());
    456   EXPECT_EQ(memcmp(&full_hashes[0].hash,
    457                    "zzzzyyyyxxxxwwwwvvvvuuuuttttssss",
    458                    sizeof(SBFullHash)), 0);
    459   EXPECT_EQ(safe_browsing_util::MALWARE, full_hashes[0].list_id);
    460   EXPECT_EQ(std::string("ab"), full_hashes[0].metadata);
    461   EXPECT_EQ(memcmp(&full_hashes[1].hash,
    462                    "00112233445566778899aabbccddeeff",
    463                    sizeof(SBFullHash)), 0);
    464   EXPECT_EQ(safe_browsing_util::MALWARE, full_hashes[1].list_id);
    465   EXPECT_EQ(std::string("xy"), full_hashes[1].metadata);
    466   EXPECT_EQ(memcmp(&full_hashes[2].hash,
    467                    "cafebeefcafebeefdeaddeaddeaddead",
    468                    sizeof(SBFullHash)), 0);
    469   EXPECT_EQ(safe_browsing_util::PHISH, full_hashes[2].list_id);
    470   EXPECT_EQ(std::string(), full_hashes[2].metadata);
    471 }
    472 
    473 TEST(SafeBrowsingProtocolParsingTest, TestGetHashWithUnknownList) {
    474   std::string hash_response(base::StringPrintf(
    475       "45\n"
    476       "%s:32:1\n"
    477       "12345678901234567890123456789012"
    478       "googpub-phish-shavar:32:1\n"
    479       "09876543210987654321098765432109",
    480       kDefaultPhishList));
    481   std::vector<SBFullHashResult> full_hashes;
    482   base::TimeDelta cache_lifetime;
    483   EXPECT_TRUE(safe_browsing::ParseGetHash(hash_response.data(),
    484                                           hash_response.size(),
    485                                           &cache_lifetime,
    486                                           &full_hashes));
    487 
    488   ASSERT_EQ(1U, full_hashes.size());
    489   EXPECT_EQ(memcmp("12345678901234567890123456789012",
    490                    &full_hashes[0].hash, sizeof(SBFullHash)), 0);
    491   EXPECT_EQ(safe_browsing_util::PHISH, full_hashes[0].list_id);
    492 
    493   hash_response += base::StringPrintf(
    494       "%s:32:1\n"
    495       "abcdefghijklmnopqrstuvwxyz123457",
    496       kDefaultMalwareList);
    497   full_hashes.clear();
    498   EXPECT_TRUE(safe_browsing::ParseGetHash(hash_response.data(),
    499                                           hash_response.size(),
    500                                           &cache_lifetime,
    501                                           &full_hashes));
    502 
    503   EXPECT_EQ(2U, full_hashes.size());
    504   EXPECT_EQ(memcmp("12345678901234567890123456789012",
    505                    &full_hashes[0].hash, sizeof(SBFullHash)), 0);
    506   EXPECT_EQ(safe_browsing_util::PHISH, full_hashes[0].list_id);
    507   EXPECT_EQ(memcmp("abcdefghijklmnopqrstuvwxyz123457",
    508                    &full_hashes[1].hash, sizeof(SBFullHash)), 0);
    509   EXPECT_EQ(safe_browsing_util::MALWARE, full_hashes[1].list_id);
    510 }
    511 
    512 TEST(SafeBrowsingProtocolParsingTest, TestGetHashWithUnknownListAndMetadata) {
    513   std::vector<SBFullHashResult> full_hashes;
    514   base::TimeDelta cache_lifetime;
    515   // Test skipping over a hashentry with an unrecognized listname that also has
    516   // metadata.
    517   const std::string get_hash3(base::StringPrintf(
    518       "600\n"
    519       "BADLISTNAME:32:1:m\n"
    520       "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
    521       "8\nMETADATA"
    522       "%s:32:1\n"
    523       "0123456789hashhashhashhashhashha",
    524       kDefaultMalwareList));
    525   EXPECT_TRUE(safe_browsing::ParseGetHash(get_hash3.data(), get_hash3.length(),
    526                                           &cache_lifetime, &full_hashes));
    527   ASSERT_EQ(1U, full_hashes.size());
    528   EXPECT_EQ(memcmp(&full_hashes[0].hash,
    529                    "0123456789hashhashhashhashhashha",
    530                    sizeof(SBFullHash)), 0);
    531   EXPECT_EQ(safe_browsing_util::MALWARE, full_hashes[0].list_id);
    532   EXPECT_EQ(std::string(), full_hashes[0].metadata);
    533 }
    534 
    535 TEST(SafeBrowsingProtocolParsingTest, TestFormatHash) {
    536   std::vector<SBPrefix> prefixes;
    537   prefixes.push_back(0x34333231);
    538   prefixes.push_back(0x64636261);
    539   prefixes.push_back(0x73727170);
    540 
    541   EXPECT_EQ("4:12\n1234abcdpqrs", safe_browsing::FormatGetHash(prefixes));
    542 }
    543 
    544 TEST(SafeBrowsingProtocolParsingTest, TestReset) {
    545   std::string update("n:1800\ni:phishy\nr:pleasereset\n");
    546 
    547   bool reset = false;
    548   size_t next_update = 0;
    549   std::vector<SBChunkDelete> deletes;
    550   std::vector<ChunkUrl> urls;
    551   EXPECT_TRUE(safe_browsing::ParseUpdate(update.data(), update.size(),
    552                                          &next_update, &reset,
    553                                          &deletes, &urls));
    554   EXPECT_TRUE(reset);
    555 }
    556 
    557 // The SafeBrowsing service will occasionally send zero length chunks so that
    558 // client requests will have longer contiguous chunk number ranges, and thus
    559 // reduce the request size.
    560 TEST(SafeBrowsingProtocolParsingTest, TestZeroSizeAddChunk) {
    561   const char kEmptyAddChunk[] = {
    562     '\0', '\0', '\0', '\x02',  // 32-bit payload length in network byte order.
    563     '\x08',                    // field 1, wire format varint
    564     '\x02',                    // chunk_number varint 2
    565   };
    566 
    567   ScopedVector<SBChunkData> chunks;
    568   EXPECT_TRUE(safe_browsing::ParseChunk(kEmptyAddChunk, sizeof(kEmptyAddChunk),
    569                                         &chunks));
    570   ASSERT_EQ(1U, chunks.size());
    571   EXPECT_EQ(2, chunks[0]->ChunkNumber());
    572   EXPECT_TRUE(chunks[0]->IsAdd());
    573   EXPECT_FALSE(chunks[0]->IsSub());
    574   EXPECT_TRUE(chunks[0]->IsPrefix());
    575   EXPECT_FALSE(chunks[0]->IsFullHash());
    576   EXPECT_EQ(0U, chunks[0]->PrefixCount());
    577 
    578   // Now test a zero size chunk in between normal chunks.
    579   chunks.clear();
    580   const char kAddChunks[] = {
    581     '\0', '\0', '\0', '\x0C',  // 32-bit payload length in network byte order.
    582     '\x08',                    // field 1, wire format varint
    583     '\x01',                    // chunk_number varint 1
    584     '\x22',                    // field 4, wire format length-delimited
    585     '\x08',                    // varint length 8
    586 
    587     '1', '1', '1', '1',        // 4-byte prefixes
    588     '2', '2', '2', '2',
    589 
    590     '\0', '\0', '\0', '\x02',  // 32-bit payload length in network byte order.
    591     '\x08',                    // field 1, wire format varint
    592     '\x02',                    // chunk_number varint 2
    593 
    594     '\0', '\0', '\0', '\x08',  // 32-bit payload length in network byte order.
    595     '\x08',                    // field 1, wire format varint
    596     '\x03',                    // chunk_number varint 3
    597     '\x22',                    // field 4, wire format length-delimited
    598     '\x04',                    // varint length 8
    599     'p', 'p', 'p', 'p',        // 4-byte prefixes
    600   };
    601   EXPECT_TRUE(safe_browsing::ParseChunk(kAddChunks, sizeof(kAddChunks),
    602                                         &chunks));
    603   ASSERT_EQ(3U, chunks.size());
    604 
    605   EXPECT_EQ(1, chunks[0]->ChunkNumber());
    606   EXPECT_TRUE(chunks[0]->IsAdd());
    607   EXPECT_FALSE(chunks[0]->IsSub());
    608   EXPECT_TRUE(chunks[0]->IsPrefix());
    609   EXPECT_FALSE(chunks[0]->IsFullHash());
    610   ASSERT_EQ(2U, chunks[0]->PrefixCount());
    611   EXPECT_EQ(0x31313131U, chunks[0]->PrefixAt(0));  // 1111
    612   EXPECT_EQ(0x32323232U, chunks[0]->PrefixAt(1));  // 2222
    613 
    614   EXPECT_EQ(2, chunks[1]->ChunkNumber());
    615   EXPECT_TRUE(chunks[1]->IsAdd());
    616   EXPECT_FALSE(chunks[1]->IsSub());
    617   EXPECT_TRUE(chunks[1]->IsPrefix());
    618   EXPECT_FALSE(chunks[1]->IsFullHash());
    619   EXPECT_EQ(0U, chunks[1]->PrefixCount());
    620 
    621   EXPECT_EQ(3, chunks[2]->ChunkNumber());
    622   EXPECT_TRUE(chunks[2]->IsAdd());
    623   EXPECT_FALSE(chunks[2]->IsSub());
    624   EXPECT_TRUE(chunks[2]->IsPrefix());
    625   EXPECT_FALSE(chunks[2]->IsFullHash());
    626   ASSERT_EQ(1U, chunks[2]->PrefixCount());
    627   EXPECT_EQ(0x70707070U, chunks[2]->PrefixAt(0));  // pppp
    628 }
    629 
    630 // Test parsing a zero sized sub chunk.
    631 TEST(SafeBrowsingProtocolParsingTest, TestZeroSizeSubChunk) {
    632   const char kEmptySubChunk[] = {
    633     '\0', '\0', '\0', '\x04',  // 32-bit payload length in network byte order.
    634     '\x08',                    // field 1, wire format varint
    635     '\x02',                    // chunk_number varint 2
    636     '\x10',                    // field 2, wire format varint
    637     '\x01',                    // enum ChunkType == SUB
    638   };
    639 
    640   ScopedVector<SBChunkData> chunks;
    641   EXPECT_TRUE(safe_browsing::ParseChunk(kEmptySubChunk, sizeof(kEmptySubChunk),
    642                                         &chunks));
    643   ASSERT_EQ(1U, chunks.size());
    644   EXPECT_EQ(2, chunks[0]->ChunkNumber());
    645   EXPECT_FALSE(chunks[0]->IsAdd());
    646   EXPECT_TRUE(chunks[0]->IsSub());
    647   EXPECT_TRUE(chunks[0]->IsPrefix());
    648   EXPECT_FALSE(chunks[0]->IsFullHash());
    649   EXPECT_EQ(0U, chunks[0]->PrefixCount());
    650 
    651   // Test parsing a zero sized sub chunk mixed in with content carrying chunks.
    652   chunks.clear();
    653   const char kSubChunks[] = {
    654     '\0', '\0', '\0', '\x12',  // 32-bit payload length in network byte order.
    655     '\x08',                    // field 1, wire format varint
    656     '\x01',                    // chunk_number varint 1
    657     '\x10',                    // field 2, wire format varint
    658     '\x01',                    // enum ChunkType == SUB
    659     '\x22',                    // field 4, wire format length-delimited
    660     '\x08',                    // varint length 8
    661     '1', '1', '1', '1',        // 4-byte prefixes
    662     '2', '2', '2', '2',
    663     '\x2a',                    // field 5, wire format length-delimited
    664     '\x02',                    // varint length 2 (2 add-chunk numbers)
    665     '\x07', '\x09',            // varint 7, varint 9
    666 
    667     '\0', '\0', '\0', '\x04',  // 32-bit payload length in network byte order.
    668     '\x08',                    // field 1, wire format varint
    669     '\x02',                    // chunk_number varint 2
    670     '\x10',                    // field 2, wire format varint
    671     '\x01',                    // enum ChunkType == SUB
    672 
    673     '\0', '\0', '\0', '\x0D',  // 32-bit payload length in network byte order.
    674     '\x08',                    // field 1, wire format varint
    675     '\x03',                    // chunk_number varint 3
    676     '\x10',                    // field 2, wire format varint
    677     '\x01',                    // enum ChunkType == SUB
    678     '\x22',                    // field 4, wire format length-delimited
    679     '\x04',                    // varint length 8
    680     'p', 'p', 'p', 'p',        // 4-byte prefix
    681     '\x2a',                    // field 5, wire format length-delimited
    682     '\x01',                    // varint length 1 (1 add-chunk numbers)
    683     '\x0B',                    // varint 11
    684   };
    685 
    686   EXPECT_TRUE(safe_browsing::ParseChunk(kSubChunks, sizeof(kSubChunks),
    687                                         &chunks));
    688   ASSERT_EQ(3U, chunks.size());
    689 
    690   EXPECT_EQ(1, chunks[0]->ChunkNumber());
    691   EXPECT_FALSE(chunks[0]->IsAdd());
    692   EXPECT_TRUE(chunks[0]->IsSub());
    693   EXPECT_TRUE(chunks[0]->IsPrefix());
    694   EXPECT_FALSE(chunks[0]->IsFullHash());
    695   ASSERT_EQ(2U, chunks[0]->PrefixCount());
    696   EXPECT_EQ(0x31313131U, chunks[0]->PrefixAt(0));  // 1111
    697   EXPECT_EQ(7, chunks[0]->AddChunkNumberAt(0));
    698   EXPECT_EQ(0x32323232U, chunks[0]->PrefixAt(1));  // 2222
    699   EXPECT_EQ(9, chunks[0]->AddChunkNumberAt(1));
    700 
    701   EXPECT_EQ(2, chunks[1]->ChunkNumber());
    702   EXPECT_FALSE(chunks[0]->IsAdd());
    703   EXPECT_TRUE(chunks[0]->IsSub());
    704   EXPECT_TRUE(chunks[1]->IsPrefix());
    705   EXPECT_FALSE(chunks[1]->IsFullHash());
    706   EXPECT_EQ(0U, chunks[1]->PrefixCount());
    707 
    708   EXPECT_EQ(3, chunks[2]->ChunkNumber());
    709   EXPECT_FALSE(chunks[0]->IsAdd());
    710   EXPECT_TRUE(chunks[0]->IsSub());
    711   EXPECT_TRUE(chunks[2]->IsPrefix());
    712   EXPECT_FALSE(chunks[2]->IsFullHash());
    713   ASSERT_EQ(1U, chunks[2]->PrefixCount());
    714   EXPECT_EQ(0x70707070U, chunks[2]->PrefixAt(0));  // pppp
    715   EXPECT_EQ(11, chunks[2]->AddChunkNumberAt(0));
    716 }
    717 
    718 }  // namespace
    719