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