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 
      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 
     24 using base::Time;
     25 using base::TimeDelta;
     26 using testing::_;
     27 using testing::Invoke;
     28 
     29 namespace {
     30 
     31 const char kUrlPrefix[] = "https://prefix.com/foo";
     32 const char kBackupConnectUrlPrefix[] = "https://alt1-prefix.com/foo";
     33 const char kBackupHttpUrlPrefix[] = "https://alt2-prefix.com/foo";
     34 const char kBackupNetworkUrlPrefix[] = "https://alt3-prefix.com/foo";
     35 const char kClient[] = "unittest";
     36 const char kAppVer[] = "1.0";
     37 const char kAdditionalQuery[] = "additional_query";
     38 
     39 #if defined(OS_ANDROID)
     40 const char kDefaultPhishList[] = "goog-mobilephish-shavar";
     41 const char kDefaultMalwareList[] = "goog-mobilemalware-shavar";
     42 #else
     43 const char kDefaultPhishList[] = "goog-phish-shavar";
     44 const char kDefaultMalwareList[] = "goog-malware-shavar";
     45 #endif
     46 
     47 // Add-prefix chunk with single prefix.
     48 const 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 };
     56 const std::string kChunkPayload1(kRawChunkPayload1, sizeof(kRawChunkPayload1));
     57 
     58 // Add-prefix chunk_number 5 with single prefix.
     59 const 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 };
     67 const std::string kChunkPayload2(kRawChunkPayload2, sizeof(kRawChunkPayload2));
     68 
     69 }  // namespace
     70 
     71 class 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.
    129 TEST_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 
    178 TEST_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 
    209 TEST_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 
    261 TEST_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 
    273 TEST_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 
    285 TEST_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 
    313 namespace {
    314 
    315 class 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?
    349 void 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.
    360 void 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.
    375 TEST_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.
    400 TEST_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 
    453 TEST_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.
    501 TEST_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.
    548 TEST_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.
    596 TEST_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.
    646 TEST_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.
    694 TEST_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.
    741 TEST_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.
    790 TEST_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.
    838 TEST_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.
    883 TEST_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.
    919 TEST_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.
    966 TEST_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.
   1013 TEST_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.
   1067 TEST_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