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