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