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