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