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
6#include "base/memory/scoped_ptr.h"
7#include "base/memory/scoped_vector.h"
8#include "base/strings/stringprintf.h"
9#include "base/test/test_simple_task_runner.h"
10#include "base/thread_task_runner_handle.h"
11#include "base/time/time.h"
12#include "chrome/browser/safe_browsing/chunk.pb.h"
13#include "chrome/browser/safe_browsing/protocol_manager.h"
14#include "chrome/browser/safe_browsing/safe_browsing_util.h"
15#include "google_apis/google_api_keys.h"
16#include "net/base/escape.h"
17#include "net/base/load_flags.h"
18#include "net/base/net_errors.h"
19#include "net/url_request/test_url_fetcher_factory.h"
20#include "testing/gmock/include/gmock/gmock.h"
21#include "testing/gmock_mutant.h"
22#include "testing/gtest/include/gtest/gtest.h"
23
24using base::Time;
25using base::TimeDelta;
26using testing::_;
27using testing::Invoke;
28
29namespace {
30
31const char kUrlPrefix[] = "https://prefix.com/foo";
32const char kBackupConnectUrlPrefix[] = "https://alt1-prefix.com/foo";
33const char kBackupHttpUrlPrefix[] = "https://alt2-prefix.com/foo";
34const char kBackupNetworkUrlPrefix[] = "https://alt3-prefix.com/foo";
35const char kClient[] = "unittest";
36const char kAppVer[] = "1.0";
37const char kAdditionalQuery[] = "additional_query";
38
39#if defined(OS_ANDROID)
40const char kDefaultPhishList[] = "goog-mobilephish-shavar";
41const char kDefaultMalwareList[] = "goog-mobilemalware-shavar";
42#else
43const char kDefaultPhishList[] = "goog-phish-shavar";
44const char kDefaultMalwareList[] = "goog-malware-shavar";
45#endif
46
47// Add-prefix chunk with single prefix.
48const char kRawChunkPayload1[] = {
49  '\0', '\0', '\0', '\x08',  // 32-bit payload length in network byte order.
50  '\x08',                    // field 1, wire format varint
51  '\x03',                    // chunk_number varint 3
52  '\x22',                    // field 4, wire format length-delimited
53  '\x04',                    // varint 4 length
54  'a', 'b', 'c', 'd'         // 4-byte prefix
55};
56const std::string kChunkPayload1(kRawChunkPayload1, sizeof(kRawChunkPayload1));
57
58// Add-prefix chunk_number 5 with single prefix.
59const char kRawChunkPayload2[] = {
60  '\0', '\0', '\0', '\x08',  // 32-bit payload length in network byte order.
61  '\x08',                    // field 1, wire format varint
62  '\x05',                    // chunk_number varint 5
63  '\x22',                    // field 4, wire format length-delimited
64  '\x04',                    // varint length 4
65  'e', 'f', 'g', 'h'         // 4-byte prefix
66};
67const std::string kChunkPayload2(kRawChunkPayload2, sizeof(kRawChunkPayload2));
68
69}  // namespace
70
71class SafeBrowsingProtocolManagerTest : public testing::Test {
72 protected:
73  std::string key_param_;
74
75  virtual void SetUp() {
76    std::string key = google_apis::GetAPIKey();
77    if (!key.empty()) {
78      key_param_ = base::StringPrintf(
79          "&key=%s",
80          net::EscapeQueryParamValue(key, true).c_str());
81    }
82  }
83
84  scoped_ptr<SafeBrowsingProtocolManager> CreateProtocolManager(
85      SafeBrowsingProtocolManagerDelegate* delegate) {
86    SafeBrowsingProtocolConfig config;
87    config.client_name = kClient;
88    config.url_prefix = kUrlPrefix;
89    config.backup_connect_error_url_prefix = kBackupConnectUrlPrefix;
90    config.backup_http_error_url_prefix = kBackupHttpUrlPrefix;
91    config.backup_network_error_url_prefix = kBackupNetworkUrlPrefix;
92    config.version = kAppVer;
93#if defined(OS_ANDROID)
94    config.disable_connection_check = true;
95#endif
96    return scoped_ptr<SafeBrowsingProtocolManager>(
97        SafeBrowsingProtocolManager::Create(delegate, NULL, config));
98  }
99
100  void ValidateUpdateFetcherRequest(
101      const net::TestURLFetcher* url_fetcher,
102      const std::string& expected_prefix) {
103    ASSERT_TRUE(url_fetcher);
104    EXPECT_EQ(net::LOAD_DISABLE_CACHE, url_fetcher->GetLoadFlags());
105
106    std::string expected_lists(base::StringPrintf("%s;\n%s;\n",
107                                                  kDefaultPhishList,
108                                                  kDefaultMalwareList));
109    EXPECT_EQ(expected_lists, url_fetcher->upload_data());
110    EXPECT_EQ(GURL(expected_prefix + "/downloads?client=unittest&appver=1.0"
111                   "&pver=3.0" + key_param_),
112              url_fetcher->GetOriginalURL());
113  }
114
115  void ValidateUpdateFetcherRequest(const net::TestURLFetcher* url_fetcher) {
116    ValidateUpdateFetcherRequest(url_fetcher, kUrlPrefix);
117  }
118
119  void ValidateRedirectFetcherRequest(const net::TestURLFetcher* url_fetcher,
120                                      const std::string& expected_url) {
121    ASSERT_TRUE(url_fetcher);
122    EXPECT_EQ(net::LOAD_DISABLE_CACHE, url_fetcher->GetLoadFlags());
123    EXPECT_EQ("", url_fetcher->upload_data());
124    EXPECT_EQ(GURL(expected_url), url_fetcher->GetOriginalURL());
125  }
126};
127
128// Ensure that we respect section 5 of the SafeBrowsing protocol specification.
129TEST_F(SafeBrowsingProtocolManagerTest, TestBackOffTimes) {
130  scoped_ptr<SafeBrowsingProtocolManager> pm(CreateProtocolManager(NULL));
131
132  pm->next_update_interval_ = TimeDelta::FromSeconds(1800);
133  ASSERT_TRUE(pm->back_off_fuzz_ >= 0.0 && pm->back_off_fuzz_ <= 1.0);
134
135  TimeDelta next;
136
137  // No errors received so far.
138  next = pm->GetNextUpdateInterval(false);
139  EXPECT_EQ(next, TimeDelta::FromSeconds(1800));
140
141  // 1 error.
142  next = pm->GetNextUpdateInterval(true);
143  EXPECT_EQ(next, TimeDelta::FromSeconds(60));
144
145  // 2 errors.
146  next = pm->GetNextUpdateInterval(true);
147  EXPECT_TRUE(next >= TimeDelta::FromMinutes(30) &&
148              next <= TimeDelta::FromMinutes(60));
149
150  // 3 errors.
151  next = pm->GetNextUpdateInterval(true);
152  EXPECT_TRUE(next >= TimeDelta::FromMinutes(60) &&
153              next <= TimeDelta::FromMinutes(120));
154
155  // 4 errors.
156  next = pm->GetNextUpdateInterval(true);
157  EXPECT_TRUE(next >= TimeDelta::FromMinutes(120) &&
158              next <= TimeDelta::FromMinutes(240));
159
160  // 5 errors.
161  next = pm->GetNextUpdateInterval(true);
162  EXPECT_TRUE(next >= TimeDelta::FromMinutes(240) &&
163              next <= TimeDelta::FromMinutes(480));
164
165  // 6 errors, reached max backoff.
166  next = pm->GetNextUpdateInterval(true);
167  EXPECT_EQ(next, TimeDelta::FromMinutes(480));
168
169  // 7 errors.
170  next = pm->GetNextUpdateInterval(true);
171  EXPECT_EQ(next, TimeDelta::FromMinutes(480));
172
173  // Received a successful response.
174  next = pm->GetNextUpdateInterval(false);
175  EXPECT_EQ(next, TimeDelta::FromSeconds(1800));
176}
177
178TEST_F(SafeBrowsingProtocolManagerTest, TestChunkStrings) {
179  scoped_ptr<SafeBrowsingProtocolManager> pm(CreateProtocolManager(NULL));
180
181  // Add and Sub chunks.
182  SBListChunkRanges phish(kDefaultPhishList);
183  phish.adds = "1,4,6,8-20,99";
184  phish.subs = "16,32,64-96";
185  EXPECT_EQ(base::StringPrintf("%s;a:1,4,6,8-20,99:s:16,32,64-96\n",
186                               kDefaultPhishList),
187            safe_browsing::FormatList(phish));
188
189  // Add chunks only.
190  phish.subs = "";
191  EXPECT_EQ(base::StringPrintf("%s;a:1,4,6,8-20,99\n",
192                               kDefaultPhishList),
193            safe_browsing::FormatList(phish));
194
195  // Sub chunks only.
196  phish.adds = "";
197  phish.subs = "16,32,64-96";
198  EXPECT_EQ(base::StringPrintf("%s;s:16,32,64-96\n",
199                               kDefaultPhishList),
200            safe_browsing::FormatList(phish));
201
202  // No chunks of either type.
203  phish.adds = "";
204  phish.subs = "";
205  EXPECT_EQ(base::StringPrintf("%s;\n", kDefaultPhishList),
206            safe_browsing::FormatList(phish));
207}
208
209TEST_F(SafeBrowsingProtocolManagerTest, TestGetHashBackOffTimes) {
210  scoped_ptr<SafeBrowsingProtocolManager> pm(CreateProtocolManager(NULL));
211
212  // No errors or back off time yet.
213  EXPECT_EQ(0U, pm->gethash_error_count_);
214  EXPECT_TRUE(pm->next_gethash_time_.is_null());
215
216  Time now = Time::Now();
217
218  // 1 error.
219  pm->HandleGetHashError(now);
220  EXPECT_EQ(1U, pm->gethash_error_count_);
221  TimeDelta margin = TimeDelta::FromSeconds(5);  // Fudge factor.
222  Time future = now + TimeDelta::FromMinutes(1);
223  EXPECT_TRUE(pm->next_gethash_time_ >= future - margin &&
224              pm->next_gethash_time_ <= future + margin);
225
226  // 2 errors.
227  pm->HandleGetHashError(now);
228  EXPECT_EQ(2U, pm->gethash_error_count_);
229  EXPECT_TRUE(pm->next_gethash_time_ >= now + TimeDelta::FromMinutes(30));
230  EXPECT_TRUE(pm->next_gethash_time_ <= now + TimeDelta::FromMinutes(60));
231
232  // 3 errors.
233  pm->HandleGetHashError(now);
234  EXPECT_EQ(3U, pm->gethash_error_count_);
235  EXPECT_TRUE(pm->next_gethash_time_ >= now + TimeDelta::FromMinutes(60));
236  EXPECT_TRUE(pm->next_gethash_time_ <= now + TimeDelta::FromMinutes(120));
237
238  // 4 errors.
239  pm->HandleGetHashError(now);
240  EXPECT_EQ(4U, pm->gethash_error_count_);
241  EXPECT_TRUE(pm->next_gethash_time_ >= now + TimeDelta::FromMinutes(120));
242  EXPECT_TRUE(pm->next_gethash_time_ <= now + TimeDelta::FromMinutes(240));
243
244  // 5 errors.
245  pm->HandleGetHashError(now);
246  EXPECT_EQ(5U, pm->gethash_error_count_);
247  EXPECT_TRUE(pm->next_gethash_time_ >= now + TimeDelta::FromMinutes(240));
248  EXPECT_TRUE(pm->next_gethash_time_ <= now + TimeDelta::FromMinutes(480));
249
250  // 6 errors, reached max backoff.
251  pm->HandleGetHashError(now);
252  EXPECT_EQ(6U, pm->gethash_error_count_);
253  EXPECT_TRUE(pm->next_gethash_time_ == now + TimeDelta::FromMinutes(480));
254
255  // 7 errors.
256  pm->HandleGetHashError(now);
257  EXPECT_EQ(7U, pm->gethash_error_count_);
258  EXPECT_TRUE(pm->next_gethash_time_== now + TimeDelta::FromMinutes(480));
259}
260
261TEST_F(SafeBrowsingProtocolManagerTest, TestGetHashUrl) {
262  scoped_ptr<SafeBrowsingProtocolManager> pm(CreateProtocolManager(NULL));
263
264  EXPECT_EQ("https://prefix.com/foo/gethash?client=unittest&appver=1.0&"
265            "pver=3.0" + key_param_, pm->GetHashUrl().spec());
266
267  pm->set_additional_query(kAdditionalQuery);
268  EXPECT_EQ("https://prefix.com/foo/gethash?client=unittest&appver=1.0&"
269            "pver=3.0" + key_param_ + "&additional_query",
270            pm->GetHashUrl().spec());
271}
272
273TEST_F(SafeBrowsingProtocolManagerTest, TestUpdateUrl) {
274  scoped_ptr<SafeBrowsingProtocolManager> pm(CreateProtocolManager(NULL));
275
276  EXPECT_EQ("https://prefix.com/foo/downloads?client=unittest&appver=1.0&"
277            "pver=3.0" + key_param_, pm->UpdateUrl().spec());
278
279  pm->set_additional_query(kAdditionalQuery);
280  EXPECT_EQ("https://prefix.com/foo/downloads?client=unittest&appver=1.0&"
281            "pver=3.0" + key_param_ + "&additional_query",
282            pm->UpdateUrl().spec());
283}
284
285TEST_F(SafeBrowsingProtocolManagerTest, TestNextChunkUrl) {
286  scoped_ptr<SafeBrowsingProtocolManager> pm(CreateProtocolManager(NULL));
287
288  std::string url_partial = "localhost:1234/foo/bar?foo";
289  std::string url_http_full = "http://localhost:1234/foo/bar?foo";
290  std::string url_https_full = "https://localhost:1234/foo/bar?foo";
291  std::string url_https_no_query = "https://localhost:1234/foo/bar";
292
293  EXPECT_EQ("https://localhost:1234/foo/bar?foo",
294            pm->NextChunkUrl(url_partial).spec());
295  EXPECT_EQ("http://localhost:1234/foo/bar?foo",
296            pm->NextChunkUrl(url_http_full).spec());
297  EXPECT_EQ("https://localhost:1234/foo/bar?foo",
298            pm->NextChunkUrl(url_https_full).spec());
299  EXPECT_EQ("https://localhost:1234/foo/bar",
300            pm->NextChunkUrl(url_https_no_query).spec());
301
302  pm->set_additional_query(kAdditionalQuery);
303  EXPECT_EQ("https://localhost:1234/foo/bar?foo&additional_query",
304            pm->NextChunkUrl(url_partial).spec());
305  EXPECT_EQ("http://localhost:1234/foo/bar?foo&additional_query",
306            pm->NextChunkUrl(url_http_full).spec());
307  EXPECT_EQ("https://localhost:1234/foo/bar?foo&additional_query",
308            pm->NextChunkUrl(url_https_full).spec());
309  EXPECT_EQ("https://localhost:1234/foo/bar?additional_query",
310            pm->NextChunkUrl(url_https_no_query).spec());
311}
312
313namespace {
314
315class MockProtocolDelegate : public SafeBrowsingProtocolManagerDelegate {
316 public:
317  MockProtocolDelegate() {}
318  virtual ~MockProtocolDelegate() {}
319
320  MOCK_METHOD0(UpdateStarted, void());
321  MOCK_METHOD1(UpdateFinished, void(bool));
322  MOCK_METHOD0(ResetDatabase, void());
323  MOCK_METHOD1(GetChunks, void(GetChunksCallback));
324
325  // gmock does not work with scoped_ptr<> at this time.  Add a local method to
326  // mock, then call that from an override.  Beware of object ownership when
327  // making changes here.
328  MOCK_METHOD3(AddChunksRaw, void(const std::string& lists,
329                                  const ScopedVector<SBChunkData>& chunks,
330                                  AddChunksCallback));
331  virtual void AddChunks(const std::string& list,
332                         scoped_ptr<ScopedVector<SBChunkData> > chunks,
333                         AddChunksCallback callback) OVERRIDE {
334    AddChunksRaw(list, *chunks, callback);
335  }
336
337  // TODO(shess): Actually test this case somewhere.
338  MOCK_METHOD1(DeleteChunksRaw,
339               void(const std::vector<SBChunkDelete>& chunk_deletes));
340  virtual void DeleteChunks(
341      scoped_ptr<std::vector<SBChunkDelete> > chunk_deletes) OVERRIDE{
342    DeleteChunksRaw(*chunk_deletes);
343  }
344};
345
346// |InvokeGetChunksCallback| is required because GMock's InvokeArgument action
347// expects to use operator(), and a Callback only provides Run().
348// TODO(cbentzel): Use ACTION or ACTION_TEMPLATE instead?
349void InvokeGetChunksCallback(
350    const std::vector<SBListChunkRanges>& ranges,
351    bool database_error,
352    SafeBrowsingProtocolManagerDelegate::GetChunksCallback callback) {
353  callback.Run(ranges, database_error);
354}
355
356// |HandleAddChunks| deletes the chunks and asynchronously invokes
357// |callback| since SafeBrowsingProtocolManager is not re-entrant at the time
358// this is called. This guarantee is part of the
359// SafeBrowsingProtocolManagerDelegate contract.
360void HandleAddChunks(
361    const std::string& unused_list,
362    const ScopedVector<SBChunkData>& chunks,
363    SafeBrowsingProtocolManagerDelegate::AddChunksCallback callback) {
364  scoped_refptr<base::SingleThreadTaskRunner> task_runner(
365      base::ThreadTaskRunnerHandle::Get());
366  if (!task_runner.get())
367    return;
368  task_runner->PostTask(FROM_HERE, callback);
369}
370
371}  // namespace
372
373// Tests that the Update protocol will be skipped if there are problems
374// accessing the database.
375TEST_F(SafeBrowsingProtocolManagerTest, ProblemAccessingDatabase) {
376  scoped_refptr<base::TestSimpleTaskRunner> runner(
377      new base::TestSimpleTaskRunner());
378  base::ThreadTaskRunnerHandle runner_handler(runner);
379
380  testing::StrictMock<MockProtocolDelegate> test_delegate;
381  EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
382  EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
383      Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
384                                    std::vector<SBListChunkRanges>(),
385                                    true)));
386  EXPECT_CALL(test_delegate, UpdateFinished(false)).Times(1);
387
388  scoped_ptr<SafeBrowsingProtocolManager> pm(
389      CreateProtocolManager(&test_delegate));
390
391  pm->ForceScheduleNextUpdate(TimeDelta());
392  runner->RunPendingTasks();
393
394  EXPECT_TRUE(pm->IsUpdateScheduled());
395}
396
397// Tests the contents of the POST body when there are contents in the
398// local database. This is not exhaustive, as the actual list formatting
399// is covered by SafeBrowsingProtocolManagerTest.TestChunkStrings.
400TEST_F(SafeBrowsingProtocolManagerTest, ExistingDatabase) {
401  scoped_refptr<base::TestSimpleTaskRunner> runner(
402      new base::TestSimpleTaskRunner());
403  base::ThreadTaskRunnerHandle runner_handler(runner);
404  net::TestURLFetcherFactory url_fetcher_factory;
405
406  std::vector<SBListChunkRanges> ranges;
407  SBListChunkRanges range_phish(safe_browsing_util::kPhishingList);
408  range_phish.adds = "adds_phish";
409  range_phish.subs = "subs_phish";
410  ranges.push_back(range_phish);
411
412  SBListChunkRanges range_unknown("unknown_list");
413  range_unknown.adds = "adds_unknown";
414  range_unknown.subs = "subs_unknown";
415  ranges.push_back(range_unknown);
416
417  testing::StrictMock<MockProtocolDelegate> test_delegate;
418  EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
419  EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
420      Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
421                                    ranges,
422                                    false)));
423  EXPECT_CALL(test_delegate, UpdateFinished(true)).Times(1);
424
425  scoped_ptr<SafeBrowsingProtocolManager> pm(
426      CreateProtocolManager(&test_delegate));
427
428  // Kick off initialization. This returns chunks from the DB synchronously.
429  pm->ForceScheduleNextUpdate(TimeDelta());
430  runner->RunPendingTasks();
431
432  // We should have an URLFetcher at this point in time.
433  net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
434  ASSERT_TRUE(url_fetcher);
435  EXPECT_EQ(net::LOAD_DISABLE_CACHE, url_fetcher->GetLoadFlags());
436  EXPECT_EQ(base::StringPrintf("%s;a:adds_phish:s:subs_phish\n"
437                               "unknown_list;a:adds_unknown:s:subs_unknown\n"
438                               "%s;\n",
439                               kDefaultPhishList, kDefaultMalwareList),
440            url_fetcher->upload_data());
441  EXPECT_EQ(GURL("https://prefix.com/foo/downloads?client=unittest&appver=1.0"
442                 "&pver=3.0" + key_param_),
443            url_fetcher->GetOriginalURL());
444
445  url_fetcher->set_status(net::URLRequestStatus());
446  url_fetcher->set_response_code(200);
447  url_fetcher->SetResponseString(std::string());
448  url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
449
450  EXPECT_TRUE(pm->IsUpdateScheduled());
451}
452
453TEST_F(SafeBrowsingProtocolManagerTest, UpdateResponseBadBodyBackupSuccess) {
454  scoped_refptr<base::TestSimpleTaskRunner> runner(
455      new base::TestSimpleTaskRunner());
456  base::ThreadTaskRunnerHandle runner_handler(runner);
457  net::TestURLFetcherFactory url_fetcher_factory;
458
459  testing::StrictMock<MockProtocolDelegate> test_delegate;
460  EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
461  EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
462      Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
463                                    std::vector<SBListChunkRanges>(),
464                                    false)));
465  EXPECT_CALL(test_delegate, UpdateFinished(true)).Times(1);
466
467  scoped_ptr<SafeBrowsingProtocolManager> pm(
468      CreateProtocolManager(&test_delegate));
469
470  // Kick off initialization. This returns chunks from the DB synchronously.
471  pm->ForceScheduleNextUpdate(TimeDelta());
472  runner->RunPendingTasks();
473
474  // We should have an URLFetcher at this point in time.
475  net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
476  ValidateUpdateFetcherRequest(url_fetcher);
477
478  // The update response is successful, but an invalid body.
479  url_fetcher->set_status(net::URLRequestStatus());
480  url_fetcher->set_response_code(200);
481  url_fetcher->SetResponseString("THIS_IS_A_BAD_RESPONSE");
482  url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
483
484  // There should now be a backup request.
485  net::TestURLFetcher* backup_url_fetcher =
486      url_fetcher_factory.GetFetcherByID(1);
487  ValidateUpdateFetcherRequest(backup_url_fetcher,
488                               kBackupHttpUrlPrefix);
489
490  // Respond to the backup successfully.
491  backup_url_fetcher->set_status(net::URLRequestStatus());
492  backup_url_fetcher->set_response_code(200);
493  backup_url_fetcher->SetResponseString(std::string());
494  backup_url_fetcher->delegate()->OnURLFetchComplete(backup_url_fetcher);
495
496  EXPECT_TRUE(pm->IsUpdateScheduled());
497}
498
499// Tests what happens when there is an HTTP error response to the update
500// request, as well as an error response to the backup update request.
501TEST_F(SafeBrowsingProtocolManagerTest, UpdateResponseHttpErrorBackupError) {
502  scoped_refptr<base::TestSimpleTaskRunner> runner(
503      new base::TestSimpleTaskRunner());
504  base::ThreadTaskRunnerHandle runner_handler(runner);
505  net::TestURLFetcherFactory url_fetcher_factory;
506
507  testing::StrictMock<MockProtocolDelegate> test_delegate;
508  EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
509  EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
510      Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
511                                    std::vector<SBListChunkRanges>(),
512                                    false)));
513  EXPECT_CALL(test_delegate, UpdateFinished(false)).Times(1);
514
515  scoped_ptr<SafeBrowsingProtocolManager> pm(
516      CreateProtocolManager(&test_delegate));
517
518  // Kick off initialization. This returns chunks from the DB synchronously.
519  pm->ForceScheduleNextUpdate(TimeDelta());
520  runner->RunPendingTasks();
521
522  // We should have an URLFetcher at this point in time.
523  net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
524  ValidateUpdateFetcherRequest(url_fetcher);
525
526  // Go ahead and respond to it.
527  url_fetcher->set_status(net::URLRequestStatus());
528  url_fetcher->set_response_code(404);
529  url_fetcher->SetResponseString(std::string());
530  url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
531
532  // There should now be a backup request.
533  net::TestURLFetcher* backup_url_fetcher =
534      url_fetcher_factory.GetFetcherByID(1);
535  ValidateUpdateFetcherRequest(backup_url_fetcher, kBackupHttpUrlPrefix);
536
537  // Respond to the backup unsuccessfully.
538  backup_url_fetcher->set_status(net::URLRequestStatus());
539  backup_url_fetcher->set_response_code(404);
540  backup_url_fetcher->SetResponseString(std::string());
541  backup_url_fetcher->delegate()->OnURLFetchComplete(backup_url_fetcher);
542
543  EXPECT_TRUE(pm->IsUpdateScheduled());
544}
545
546// Tests what happens when there is an HTTP error response to the update
547// request, followed by a successful response to the backup update request.
548TEST_F(SafeBrowsingProtocolManagerTest, UpdateResponseHttpErrorBackupSuccess) {
549  scoped_refptr<base::TestSimpleTaskRunner> runner(
550      new base::TestSimpleTaskRunner());
551  base::ThreadTaskRunnerHandle runner_handler(runner);
552  net::TestURLFetcherFactory url_fetcher_factory;
553
554  testing::StrictMock<MockProtocolDelegate> test_delegate;
555  EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
556  EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
557      Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
558                                    std::vector<SBListChunkRanges>(),
559                                    false)));
560  EXPECT_CALL(test_delegate, UpdateFinished(true)).Times(1);
561
562  scoped_ptr<SafeBrowsingProtocolManager> pm(
563      CreateProtocolManager(&test_delegate));
564
565  // Kick off initialization. This returns chunks from the DB synchronously.
566  pm->ForceScheduleNextUpdate(TimeDelta());
567  runner->RunPendingTasks();
568
569  // We should have an URLFetcher at this point in time.
570  net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
571  ValidateUpdateFetcherRequest(url_fetcher);
572
573  // Go ahead and respond to it.
574  url_fetcher->set_status(net::URLRequestStatus());
575  url_fetcher->set_response_code(404);
576  url_fetcher->SetResponseString(std::string());
577  url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
578
579  // There should now be a backup request.
580  net::TestURLFetcher* backup_url_fetcher =
581      url_fetcher_factory.GetFetcherByID(1);
582  ValidateUpdateFetcherRequest(backup_url_fetcher,
583                               kBackupHttpUrlPrefix);
584
585  // Respond to the backup successfully.
586  backup_url_fetcher->set_status(net::URLRequestStatus());
587  backup_url_fetcher->set_response_code(200);
588  backup_url_fetcher->SetResponseString(std::string());
589  backup_url_fetcher->delegate()->OnURLFetchComplete(backup_url_fetcher);
590
591  EXPECT_TRUE(pm->IsUpdateScheduled());
592}
593
594// Tests what happens when there is an HTTP error response to the update
595// request, and a timeout on the backup update request.
596TEST_F(SafeBrowsingProtocolManagerTest, UpdateResponseHttpErrorBackupTimeout) {
597  scoped_refptr<base::TestSimpleTaskRunner> runner(
598      new base::TestSimpleTaskRunner());
599  base::ThreadTaskRunnerHandle runner_handler(runner);
600  net::TestURLFetcherFactory url_fetcher_factory;
601
602  testing::StrictMock<MockProtocolDelegate> test_delegate;
603  EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
604  EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
605      Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
606                                    std::vector<SBListChunkRanges>(),
607                                    false)));
608  EXPECT_CALL(test_delegate, UpdateFinished(false)).Times(1);
609
610  scoped_ptr<SafeBrowsingProtocolManager> pm(
611      CreateProtocolManager(&test_delegate));
612
613  // Kick off initialization. This returns chunks from the DB synchronously.
614  pm->ForceScheduleNextUpdate(TimeDelta());
615  runner->RunPendingTasks();
616
617  // We should have an URLFetcher at this point in time.
618  net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
619  ValidateUpdateFetcherRequest(url_fetcher);
620
621  // Go ahead and respond to it.
622  url_fetcher->set_status(net::URLRequestStatus());
623  url_fetcher->set_response_code(404);
624  url_fetcher->SetResponseString(std::string());
625  url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
626
627  // There should now be a backup request.
628  net::TestURLFetcher* backup_url_fetcher =
629      url_fetcher_factory.GetFetcherByID(1);
630  ValidateUpdateFetcherRequest(backup_url_fetcher, kBackupHttpUrlPrefix);
631
632  // Either one or two calls to RunPendingTasks are needed here. The first run
633  // of RunPendingTasks will run the canceled timeout task associated with
634  // the first Update request. Depending on timing, this will either directly
635  // call the timeout task from the backup request, or schedule another task
636  // to run that in the future.
637  // TODO(cbentzel): Less fragile approach.
638  runner->RunPendingTasks();
639  if (!pm->IsUpdateScheduled())
640    runner->RunPendingTasks();
641  EXPECT_TRUE(pm->IsUpdateScheduled());
642}
643
644// Tests what happens when there is a connection error when issuing the update
645// request, and an error with the backup update request.
646TEST_F(SafeBrowsingProtocolManagerTest,
647       UpdateResponseConnectionErrorBackupError) {
648  scoped_refptr<base::TestSimpleTaskRunner> runner(
649      new base::TestSimpleTaskRunner());
650  base::ThreadTaskRunnerHandle runner_handler(runner);
651  net::TestURLFetcherFactory url_fetcher_factory;
652
653  testing::StrictMock<MockProtocolDelegate> test_delegate;
654  EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
655  EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
656      Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
657                                    std::vector<SBListChunkRanges>(),
658                                    false)));
659  EXPECT_CALL(test_delegate, UpdateFinished(false)).Times(1);
660
661  scoped_ptr<SafeBrowsingProtocolManager> pm(
662      CreateProtocolManager(&test_delegate));
663
664  // Kick off initialization. This returns chunks from the DB synchronously.
665  pm->ForceScheduleNextUpdate(TimeDelta());
666  runner->RunPendingTasks();
667
668  // We should have an URLFetcher at this point in time.
669  net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
670  ValidateUpdateFetcherRequest(url_fetcher);
671
672  // Go ahead and respond to it.
673  url_fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::FAILED,
674                                                net::ERR_CONNECTION_RESET));
675  url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
676
677  // There should be a backup URLFetcher now.
678  net::TestURLFetcher* backup_url_fetcher =
679      url_fetcher_factory.GetFetcherByID(1);
680  ValidateUpdateFetcherRequest(backup_url_fetcher,
681                               kBackupConnectUrlPrefix);
682
683  // Respond to the backup unsuccessfully.
684  backup_url_fetcher->set_status(net::URLRequestStatus());
685  backup_url_fetcher->set_response_code(404);
686  backup_url_fetcher->SetResponseString(std::string());
687  backup_url_fetcher->delegate()->OnURLFetchComplete(backup_url_fetcher);
688
689  EXPECT_TRUE(pm->IsUpdateScheduled());
690}
691
692// Tests what happens when there is a connection error when issuing the update
693// request, and a successful response to the backup update request.
694TEST_F(SafeBrowsingProtocolManagerTest,
695       UpdateResponseConnectionErrorBackupSuccess) {
696  scoped_refptr<base::TestSimpleTaskRunner> runner(
697      new base::TestSimpleTaskRunner());
698  base::ThreadTaskRunnerHandle runner_handler(runner);
699  net::TestURLFetcherFactory url_fetcher_factory;
700
701  testing::StrictMock<MockProtocolDelegate> test_delegate;
702  EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
703  EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
704      Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
705                                    std::vector<SBListChunkRanges>(),
706                                    false)));
707  EXPECT_CALL(test_delegate, UpdateFinished(true)).Times(1);
708
709  scoped_ptr<SafeBrowsingProtocolManager> pm(
710      CreateProtocolManager(&test_delegate));
711
712  // Kick off initialization. This returns chunks from the DB synchronously.
713  pm->ForceScheduleNextUpdate(TimeDelta());
714  runner->RunPendingTasks();
715
716  // We should have an URLFetcher at this point in time.
717  net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
718  ValidateUpdateFetcherRequest(url_fetcher);
719
720  // Go ahead and respond to it.
721  url_fetcher->set_status(net::URLRequestStatus(net::URLRequestStatus::FAILED,
722                                                net::ERR_CONNECTION_RESET));
723  url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
724
725  // There should be a backup URLFetcher now.
726  net::TestURLFetcher* backup_url_fetcher =
727      url_fetcher_factory.GetFetcherByID(1);
728  ValidateUpdateFetcherRequest(backup_url_fetcher,
729                               kBackupConnectUrlPrefix);
730
731  // Respond to the backup unsuccessfully.
732  backup_url_fetcher->set_status(net::URLRequestStatus());
733  backup_url_fetcher->set_response_code(200);
734  backup_url_fetcher->SetResponseString(std::string());
735  backup_url_fetcher->delegate()->OnURLFetchComplete(backup_url_fetcher);
736
737  EXPECT_TRUE(pm->IsUpdateScheduled());
738}
739// Tests what happens when there is a network state error when issuing the
740// update request, and an error with the backup update request.
741TEST_F(SafeBrowsingProtocolManagerTest,
742       UpdateResponseNetworkErrorBackupError) {
743  scoped_refptr<base::TestSimpleTaskRunner> runner(
744      new base::TestSimpleTaskRunner());
745  base::ThreadTaskRunnerHandle runner_handler(runner);
746  net::TestURLFetcherFactory url_fetcher_factory;
747
748  testing::StrictMock<MockProtocolDelegate> test_delegate;
749  EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
750  EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
751      Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
752                                    std::vector<SBListChunkRanges>(),
753                                    false)));
754  EXPECT_CALL(test_delegate, UpdateFinished(false)).Times(1);
755
756  scoped_ptr<SafeBrowsingProtocolManager> pm(
757      CreateProtocolManager(&test_delegate));
758
759  // Kick off initialization. This returns chunks from the DB synchronously.
760  pm->ForceScheduleNextUpdate(TimeDelta());
761  runner->RunPendingTasks();
762
763  // We should have an URLFetcher at this point in time.
764  net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
765  ValidateUpdateFetcherRequest(url_fetcher);
766
767  // Go ahead and respond to it.
768  url_fetcher->set_status(
769      net::URLRequestStatus(net::URLRequestStatus::FAILED,
770                            net::ERR_INTERNET_DISCONNECTED));
771  url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
772
773  // There should be a backup URLFetcher now.
774  net::TestURLFetcher* backup_url_fetcher =
775      url_fetcher_factory.GetFetcherByID(1);
776  ValidateUpdateFetcherRequest(backup_url_fetcher,
777                               kBackupNetworkUrlPrefix);
778
779  // Respond to the backup unsuccessfully.
780  backup_url_fetcher->set_status(net::URLRequestStatus());
781  backup_url_fetcher->set_response_code(404);
782  backup_url_fetcher->SetResponseString(std::string());
783  backup_url_fetcher->delegate()->OnURLFetchComplete(backup_url_fetcher);
784
785  EXPECT_TRUE(pm->IsUpdateScheduled());
786}
787
788// Tests what happens when there is a network state error when issuing the
789// update request, and a successful response to the backup update request.
790TEST_F(SafeBrowsingProtocolManagerTest,
791       UpdateResponseNetworkErrorBackupSuccess) {
792  scoped_refptr<base::TestSimpleTaskRunner> runner(
793      new base::TestSimpleTaskRunner());
794  base::ThreadTaskRunnerHandle runner_handler(runner);
795  net::TestURLFetcherFactory url_fetcher_factory;
796
797  testing::StrictMock<MockProtocolDelegate> test_delegate;
798  EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
799  EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
800      Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
801                                    std::vector<SBListChunkRanges>(),
802                                    false)));
803  EXPECT_CALL(test_delegate, UpdateFinished(true)).Times(1);
804
805  scoped_ptr<SafeBrowsingProtocolManager> pm(
806      CreateProtocolManager(&test_delegate));
807
808  // Kick off initialization. This returns chunks from the DB synchronously.
809  pm->ForceScheduleNextUpdate(TimeDelta());
810  runner->RunPendingTasks();
811
812  // We should have an URLFetcher at this point in time.
813  net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
814  ValidateUpdateFetcherRequest(url_fetcher);
815
816  // Go ahead and respond to it.
817  url_fetcher->set_status(
818      net::URLRequestStatus(net::URLRequestStatus::FAILED,
819                            net::ERR_INTERNET_DISCONNECTED));
820  url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
821
822  // There should be a backup URLFetcher now.
823  net::TestURLFetcher* backup_url_fetcher =
824      url_fetcher_factory.GetFetcherByID(1);
825  ValidateUpdateFetcherRequest(backup_url_fetcher,
826                               kBackupNetworkUrlPrefix);
827
828  // Respond to the backup unsuccessfully.
829  backup_url_fetcher->set_status(net::URLRequestStatus());
830  backup_url_fetcher->set_response_code(200);
831  backup_url_fetcher->SetResponseString(std::string());
832  backup_url_fetcher->delegate()->OnURLFetchComplete(backup_url_fetcher);
833
834  EXPECT_TRUE(pm->IsUpdateScheduled());
835}
836
837// Tests what happens when there is a timeout before an update response.
838TEST_F(SafeBrowsingProtocolManagerTest, UpdateResponseTimeoutBackupSuccess) {
839  scoped_refptr<base::TestSimpleTaskRunner> runner(
840      new base::TestSimpleTaskRunner());
841  base::ThreadTaskRunnerHandle runner_handler(runner);
842  net::TestURLFetcherFactory url_fetcher_factory;
843
844  testing::StrictMock<MockProtocolDelegate> test_delegate;
845  EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
846  EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
847      Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
848                                    std::vector<SBListChunkRanges>(),
849                                    false)));
850  EXPECT_CALL(test_delegate, UpdateFinished(true)).Times(1);
851
852  scoped_ptr<SafeBrowsingProtocolManager> pm(
853      CreateProtocolManager(&test_delegate));
854
855  // Kick off initialization. This returns chunks from the DB synchronously.
856  pm->ForceScheduleNextUpdate(TimeDelta());
857  runner->RunPendingTasks();
858
859  // We should have an URLFetcher at this point in time.
860  net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
861  ValidateUpdateFetcherRequest(url_fetcher);
862
863  // The first time RunPendingTasks is called above, the update timeout timer is
864  // not handled. This call of RunPendingTasks will handle the update.
865  runner->RunPendingTasks();
866
867  // There should be a backup URLFetcher now.
868  net::TestURLFetcher* backup_url_fetcher =
869      url_fetcher_factory.GetFetcherByID(1);
870  ValidateUpdateFetcherRequest(backup_url_fetcher,
871                               kBackupConnectUrlPrefix);
872
873  // Respond to the backup unsuccessfully.
874  backup_url_fetcher->set_status(net::URLRequestStatus());
875  backup_url_fetcher->set_response_code(200);
876  backup_url_fetcher->SetResponseString(std::string());
877  backup_url_fetcher->delegate()->OnURLFetchComplete(backup_url_fetcher);
878
879  EXPECT_TRUE(pm->IsUpdateScheduled());
880}
881
882// Tests what happens when there is a reset command in the response.
883TEST_F(SafeBrowsingProtocolManagerTest, UpdateResponseReset) {
884  scoped_refptr<base::TestSimpleTaskRunner> runner(
885      new base::TestSimpleTaskRunner());
886  base::ThreadTaskRunnerHandle runner_handler(runner);
887  net::TestURLFetcherFactory url_fetcher_factory;
888
889  testing::StrictMock<MockProtocolDelegate> test_delegate;
890  EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
891  EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
892      Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
893                                    std::vector<SBListChunkRanges>(),
894                                    false)));
895  EXPECT_CALL(test_delegate, ResetDatabase()).Times(1);
896  EXPECT_CALL(test_delegate, UpdateFinished(true)).Times(1);
897
898  scoped_ptr<SafeBrowsingProtocolManager> pm(
899      CreateProtocolManager(&test_delegate));
900
901  // Kick off initialization. This returns chunks from the DB synchronously.
902  pm->ForceScheduleNextUpdate(TimeDelta());
903  runner->RunPendingTasks();
904
905  net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
906  ValidateUpdateFetcherRequest(url_fetcher);
907
908  // The update response is successful, and has a reset command.
909  url_fetcher->set_status(net::URLRequestStatus());
910  url_fetcher->set_response_code(200);
911  url_fetcher->SetResponseString("r:pleasereset\n");
912  url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
913
914  EXPECT_TRUE(pm->IsUpdateScheduled());
915}
916
917// Tests a single valid update response, followed by a single redirect response
918// that has an valid, but empty body.
919TEST_F(SafeBrowsingProtocolManagerTest, EmptyRedirectResponse) {
920  scoped_refptr<base::TestSimpleTaskRunner> runner(
921      new base::TestSimpleTaskRunner());
922  base::ThreadTaskRunnerHandle runner_handler(runner);
923  net::TestURLFetcherFactory url_fetcher_factory;
924
925  testing::StrictMock<MockProtocolDelegate> test_delegate;
926  EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
927  EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
928      Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
929                                    std::vector<SBListChunkRanges>(),
930                                    false)));
931  EXPECT_CALL(test_delegate, UpdateFinished(true)).Times(1);
932
933  scoped_ptr<SafeBrowsingProtocolManager> pm(
934      CreateProtocolManager(&test_delegate));
935
936  // Kick off initialization. This returns chunks from the DB synchronously.
937  pm->ForceScheduleNextUpdate(TimeDelta());
938  runner->RunPendingTasks();
939
940  // The update response contains a single redirect command.
941  net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
942  ValidateUpdateFetcherRequest(url_fetcher);
943  url_fetcher->set_status(net::URLRequestStatus());
944  url_fetcher->set_response_code(200);
945  url_fetcher->SetResponseString(
946      base::StringPrintf("i:%s\n"
947                         "u:redirect-server.example.com/path\n",
948                         kDefaultPhishList));
949  url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
950
951  // The redirect response contains an empty body.
952  net::TestURLFetcher* chunk_url_fetcher =
953      url_fetcher_factory.GetFetcherByID(1);
954  ValidateRedirectFetcherRequest(
955      chunk_url_fetcher, "https://redirect-server.example.com/path");
956  chunk_url_fetcher->set_status(net::URLRequestStatus());
957  chunk_url_fetcher->set_response_code(200);
958  chunk_url_fetcher->SetResponseString(std::string());
959  chunk_url_fetcher->delegate()->OnURLFetchComplete(chunk_url_fetcher);
960
961  EXPECT_TRUE(pm->IsUpdateScheduled());
962}
963
964// Tests a single valid update response, followed by a single redirect response
965// that has an invalid body.
966TEST_F(SafeBrowsingProtocolManagerTest, InvalidRedirectResponse) {
967  scoped_refptr<base::TestSimpleTaskRunner> runner(
968      new base::TestSimpleTaskRunner());
969  base::ThreadTaskRunnerHandle runner_handler(runner);
970  net::TestURLFetcherFactory url_fetcher_factory;
971
972  testing::StrictMock<MockProtocolDelegate> test_delegate;
973  EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
974  EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
975      Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
976                                    std::vector<SBListChunkRanges>(),
977                                    false)));
978  EXPECT_CALL(test_delegate, UpdateFinished(false)).Times(1);
979
980  scoped_ptr<SafeBrowsingProtocolManager> pm(
981      CreateProtocolManager(&test_delegate));
982
983  // Kick off initialization. This returns chunks from the DB synchronously.
984  pm->ForceScheduleNextUpdate(TimeDelta());
985  runner->RunPendingTasks();
986
987  // The update response contains a single redirect command.
988  net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
989  ValidateUpdateFetcherRequest(url_fetcher);
990  url_fetcher->set_status(net::URLRequestStatus());
991  url_fetcher->set_response_code(200);
992  url_fetcher->SetResponseString(
993      base::StringPrintf("i:%s\n"
994                         "u:redirect-server.example.com/path\n",
995                         kDefaultPhishList));
996  url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
997
998  // The redirect response contains an invalid body.
999  net::TestURLFetcher* chunk_url_fetcher =
1000      url_fetcher_factory.GetFetcherByID(1);
1001  ValidateRedirectFetcherRequest(
1002      chunk_url_fetcher, "https://redirect-server.example.com/path");
1003  chunk_url_fetcher->set_status(net::URLRequestStatus());
1004  chunk_url_fetcher->set_response_code(200);
1005  chunk_url_fetcher->SetResponseString("THIS IS AN INVALID RESPONSE");
1006  chunk_url_fetcher->delegate()->OnURLFetchComplete(chunk_url_fetcher);
1007
1008  EXPECT_TRUE(pm->IsUpdateScheduled());
1009}
1010
1011// Tests a single valid update response, followed by a single redirect response
1012// containing chunks.
1013TEST_F(SafeBrowsingProtocolManagerTest, SingleRedirectResponseWithChunks) {
1014  scoped_refptr<base::TestSimpleTaskRunner> runner(
1015      new base::TestSimpleTaskRunner());
1016  base::ThreadTaskRunnerHandle runner_handler(runner);
1017  net::TestURLFetcherFactory url_fetcher_factory;
1018
1019  testing::StrictMock<MockProtocolDelegate> test_delegate;
1020  EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
1021  EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
1022      Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
1023                                    std::vector<SBListChunkRanges>(),
1024                                    false)));
1025  EXPECT_CALL(test_delegate, AddChunksRaw(kDefaultPhishList, _, _)).WillOnce(
1026      Invoke(HandleAddChunks));
1027  EXPECT_CALL(test_delegate, UpdateFinished(true)).Times(1);
1028
1029  scoped_ptr<SafeBrowsingProtocolManager> pm(
1030      CreateProtocolManager(&test_delegate));
1031
1032  // Kick off initialization. This returns chunks from the DB synchronously.
1033  pm->ForceScheduleNextUpdate(TimeDelta());
1034  runner->RunPendingTasks();
1035
1036  // The update response contains a single redirect command.
1037  net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
1038  ValidateUpdateFetcherRequest(url_fetcher);
1039  url_fetcher->set_status(net::URLRequestStatus());
1040  url_fetcher->set_response_code(200);
1041  url_fetcher->SetResponseString(
1042      base::StringPrintf("i:%s\n"
1043                         "u:redirect-server.example.com/path\n",
1044                         kDefaultPhishList));
1045  url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
1046
1047  // The redirect response contains a single chunk.
1048  net::TestURLFetcher* chunk_url_fetcher =
1049      url_fetcher_factory.GetFetcherByID(1);
1050  ValidateRedirectFetcherRequest(
1051      chunk_url_fetcher, "https://redirect-server.example.com/path");
1052  chunk_url_fetcher->set_status(net::URLRequestStatus());
1053  chunk_url_fetcher->set_response_code(200);
1054  chunk_url_fetcher->SetResponseString(kChunkPayload1);
1055  chunk_url_fetcher->delegate()->OnURLFetchComplete(chunk_url_fetcher);
1056
1057  EXPECT_FALSE(pm->IsUpdateScheduled());
1058
1059  // The AddChunksCallback needs to be invoked.
1060  runner->RunPendingTasks();
1061
1062  EXPECT_TRUE(pm->IsUpdateScheduled());
1063}
1064
1065// Tests a single valid update response, followed by multiple redirect responses
1066// containing chunks.
1067TEST_F(SafeBrowsingProtocolManagerTest, MultipleRedirectResponsesWithChunks) {
1068  scoped_refptr<base::TestSimpleTaskRunner> runner(
1069      new base::TestSimpleTaskRunner());
1070  base::ThreadTaskRunnerHandle runner_handler(runner);
1071  net::TestURLFetcherFactory url_fetcher_factory;
1072
1073  testing::StrictMock<MockProtocolDelegate> test_delegate;
1074  EXPECT_CALL(test_delegate, UpdateStarted()).Times(1);
1075  EXPECT_CALL(test_delegate, GetChunks(_)).WillOnce(
1076      Invoke(testing::CreateFunctor(InvokeGetChunksCallback,
1077                                    std::vector<SBListChunkRanges>(),
1078                                    false)));
1079  EXPECT_CALL(test_delegate, AddChunksRaw(kDefaultPhishList, _, _)).
1080      WillRepeatedly(Invoke(HandleAddChunks));
1081  EXPECT_CALL(test_delegate, UpdateFinished(true)).Times(1);
1082
1083  scoped_ptr<SafeBrowsingProtocolManager> pm(
1084      CreateProtocolManager(&test_delegate));
1085
1086  // Kick off initialization. This returns chunks from the DB synchronously.
1087  pm->ForceScheduleNextUpdate(TimeDelta());
1088  runner->RunPendingTasks();
1089
1090  // The update response contains multiple redirect commands.
1091  net::TestURLFetcher* url_fetcher = url_fetcher_factory.GetFetcherByID(0);
1092  ValidateUpdateFetcherRequest(url_fetcher);
1093  url_fetcher->set_status(net::URLRequestStatus());
1094  url_fetcher->set_response_code(200);
1095  url_fetcher->SetResponseString(
1096      base::StringPrintf("i:%s\n"
1097                         "u:redirect-server.example.com/one\n"
1098                         "u:redirect-server.example.com/two\n",
1099                         kDefaultPhishList));
1100  url_fetcher->delegate()->OnURLFetchComplete(url_fetcher);
1101
1102  // The first redirect response contains a single chunk.
1103  net::TestURLFetcher* first_chunk_url_fetcher =
1104      url_fetcher_factory.GetFetcherByID(1);
1105  ValidateRedirectFetcherRequest(
1106      first_chunk_url_fetcher, "https://redirect-server.example.com/one");
1107  first_chunk_url_fetcher->set_status(net::URLRequestStatus());
1108  first_chunk_url_fetcher->set_response_code(200);
1109  first_chunk_url_fetcher->SetResponseString(kChunkPayload1);
1110  first_chunk_url_fetcher->delegate()->OnURLFetchComplete(
1111      first_chunk_url_fetcher);
1112
1113  // Invoke the AddChunksCallback to trigger the second request.
1114  runner->RunPendingTasks();
1115
1116  EXPECT_FALSE(pm->IsUpdateScheduled());
1117
1118  // The second redirect response contains a single chunk.
1119  net::TestURLFetcher* second_chunk_url_fetcher =
1120      url_fetcher_factory.GetFetcherByID(2);
1121  ValidateRedirectFetcherRequest(
1122      second_chunk_url_fetcher, "https://redirect-server.example.com/two");
1123  second_chunk_url_fetcher->set_status(net::URLRequestStatus());
1124  second_chunk_url_fetcher->set_response_code(200);
1125  second_chunk_url_fetcher->SetResponseString(kChunkPayload2);
1126  second_chunk_url_fetcher->delegate()->OnURLFetchComplete(
1127      second_chunk_url_fetcher);
1128
1129  EXPECT_FALSE(pm->IsUpdateScheduled());
1130
1131  // Invoke the AddChunksCallback to finish the update.
1132  runner->RunPendingTasks();
1133
1134  EXPECT_TRUE(pm->IsUpdateScheduled());
1135}
1136