| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/browser/safe_browsing/protocol_manager.h" | 5 #include "chrome/browser/safe_browsing/protocol_manager.h" |
| 6 | 6 |
| 7 #ifndef NDEBUG | 7 #ifndef NDEBUG |
| 8 #include "base/base64.h" | 8 #include "base/base64.h" |
| 9 #endif | 9 #endif |
| 10 #include "base/environment.h" | 10 #include "base/environment.h" |
| (...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 83 const std::string& client_name, | 83 const std::string& client_name, |
| 84 net::URLRequestContextGetter* request_context_getter, | 84 net::URLRequestContextGetter* request_context_getter, |
| 85 const std::string& url_prefix, | 85 const std::string& url_prefix, |
| 86 bool disable_auto_update) | 86 bool disable_auto_update) |
| 87 : sb_service_(sb_service), | 87 : sb_service_(sb_service), |
| 88 request_type_(NO_REQUEST), | 88 request_type_(NO_REQUEST), |
| 89 update_error_count_(0), | 89 update_error_count_(0), |
| 90 gethash_error_count_(0), | 90 gethash_error_count_(0), |
| 91 update_back_off_mult_(1), | 91 update_back_off_mult_(1), |
| 92 gethash_back_off_mult_(1), | 92 gethash_back_off_mult_(1), |
| 93 next_update_sec_(-1), | 93 next_update_interval_(base::TimeDelta::FromSeconds( |
| 94 base::RandInt(60, kSbTimerStartIntervalSec))), |
| 94 update_state_(FIRST_REQUEST), | 95 update_state_(FIRST_REQUEST), |
| 95 chunk_pending_to_write_(false), | 96 chunk_pending_to_write_(false), |
| 96 update_size_(0), | 97 update_size_(0), |
| 97 client_name_(client_name), | 98 client_name_(client_name), |
| 98 request_context_getter_(request_context_getter), | 99 request_context_getter_(request_context_getter), |
| 99 url_prefix_(url_prefix), | 100 url_prefix_(url_prefix), |
| 100 disable_auto_update_(disable_auto_update) { | 101 disable_auto_update_(disable_auto_update) { |
| 101 DCHECK(!url_prefix_.empty()); | 102 DCHECK(!url_prefix_.empty()); |
| 102 | 103 |
| 103 // Set the backoff multiplier fuzz to a random value between 0 and 1. | 104 // Set the backoff multiplier fuzz to a random value between 0 and 1. |
| 104 back_off_fuzz_ = static_cast<float>(base::RandDouble()); | 105 back_off_fuzz_ = static_cast<float>(base::RandDouble()); |
| 105 // The first update must happen between 1-5 minutes of start up. | |
| 106 next_update_sec_ = base::RandInt(60, kSbTimerStartIntervalSec); | |
| 107 | 106 |
| 108 chrome::VersionInfo version_info; | 107 chrome::VersionInfo version_info; |
| 109 if (!version_info.is_valid() || version_info.Version().empty()) | 108 if (!version_info.is_valid() || version_info.Version().empty()) |
| 110 version_ = "0.1"; | 109 version_ = "0.1"; |
| 111 else | 110 else |
| 112 version_ = version_info.Version(); | 111 version_ = version_info.Version(); |
| 113 } | 112 } |
| 114 | 113 |
| 115 // static | 114 // static |
| 116 void SafeBrowsingProtocolManager::RecordGetHashResult( | 115 void SafeBrowsingProtocolManager::RecordGetHashResult( |
| (...skipping 213 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 330 int next_update_sec = -1; | 329 int next_update_sec = -1; |
| 331 bool reset = false; | 330 bool reset = false; |
| 332 scoped_ptr<std::vector<SBChunkDelete> > chunk_deletes( | 331 scoped_ptr<std::vector<SBChunkDelete> > chunk_deletes( |
| 333 new std::vector<SBChunkDelete>); | 332 new std::vector<SBChunkDelete>); |
| 334 std::vector<ChunkUrl> chunk_urls; | 333 std::vector<ChunkUrl> chunk_urls; |
| 335 if (!parser.ParseUpdate(data, length, &next_update_sec, | 334 if (!parser.ParseUpdate(data, length, &next_update_sec, |
| 336 &reset, chunk_deletes.get(), &chunk_urls)) { | 335 &reset, chunk_deletes.get(), &chunk_urls)) { |
| 337 return false; | 336 return false; |
| 338 } | 337 } |
| 339 | 338 |
| 339 base::TimeDelta next_update_interval = |
| 340 base::TimeDelta::FromSeconds(next_update_sec); |
| 340 last_update_ = Time::Now(); | 341 last_update_ = Time::Now(); |
| 341 | 342 |
| 342 if (update_state_ == FIRST_REQUEST) | 343 if (update_state_ == FIRST_REQUEST) |
| 343 update_state_ = SECOND_REQUEST; | 344 update_state_ = SECOND_REQUEST; |
| 344 else if (update_state_ == SECOND_REQUEST) | 345 else if (update_state_ == SECOND_REQUEST) |
| 345 update_state_ = NORMAL_REQUEST; | 346 update_state_ = NORMAL_REQUEST; |
| 346 | 347 |
| 347 // New time for the next update. | 348 // New time for the next update. |
| 348 if (next_update_sec > 0) { | 349 if (next_update_interval > base::TimeDelta()) { |
| 349 next_update_sec_ = next_update_sec; | 350 next_update_interval_ = next_update_interval; |
| 350 } else if (update_state_ == SECOND_REQUEST) { | 351 } else if (update_state_ == SECOND_REQUEST) { |
| 351 next_update_sec_ = base::RandInt(15 * 60, 45 * 60); | 352 next_update_interval_ = base::TimeDelta::FromSeconds( |
| 353 base::RandInt(15, 45)); |
| 352 } | 354 } |
| 353 | 355 |
| 354 // New chunks to download. | 356 // New chunks to download. |
| 355 if (!chunk_urls.empty()) { | 357 if (!chunk_urls.empty()) { |
| 356 UMA_HISTOGRAM_COUNTS("SB2.UpdateUrls", chunk_urls.size()); | 358 UMA_HISTOGRAM_COUNTS("SB2.UpdateUrls", chunk_urls.size()); |
| 357 for (size_t i = 0; i < chunk_urls.size(); ++i) | 359 for (size_t i = 0; i < chunk_urls.size(); ++i) |
| 358 chunk_request_urls_.push_back(chunk_urls[i]); | 360 chunk_request_urls_.push_back(chunk_urls[i]); |
| 359 } | 361 } |
| 360 | 362 |
| 361 // Handle the case were the SafeBrowsing service tells us to dump our | 363 // Handle the case were the SafeBrowsing service tells us to dump our |
| (...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 413 void SafeBrowsingProtocolManager::Initialize() { | 415 void SafeBrowsingProtocolManager::Initialize() { |
| 414 // Don't want to hit the safe browsing servers on build/chrome bots. | 416 // Don't want to hit the safe browsing servers on build/chrome bots. |
| 415 scoped_ptr<base::Environment> env(base::Environment::Create()); | 417 scoped_ptr<base::Environment> env(base::Environment::Create()); |
| 416 if (env->HasVar(env_vars::kHeadless)) | 418 if (env->HasVar(env_vars::kHeadless)) |
| 417 return; | 419 return; |
| 418 | 420 |
| 419 ScheduleNextUpdate(false /* no back off */); | 421 ScheduleNextUpdate(false /* no back off */); |
| 420 } | 422 } |
| 421 | 423 |
| 422 void SafeBrowsingProtocolManager::ScheduleNextUpdate(bool back_off) { | 424 void SafeBrowsingProtocolManager::ScheduleNextUpdate(bool back_off) { |
| 423 DCHECK_GT(next_update_sec_, 0); | |
| 424 | |
| 425 if (disable_auto_update_) { | 425 if (disable_auto_update_) { |
| 426 // Unschedule any current timer. | 426 // Unschedule any current timer. |
| 427 update_timer_.Stop(); | 427 update_timer_.Stop(); |
| 428 return; | 428 return; |
| 429 } | 429 } |
| 430 // Reschedule with the new update. | 430 // Reschedule with the new update. |
| 431 const int next_update = GetNextUpdateTime(back_off); | 431 base::TimeDelta next_update_interval = GetNextUpdateInterval(back_off); |
| 432 ForceScheduleNextUpdate(next_update); | 432 ForceScheduleNextUpdate(next_update_interval); |
| 433 } | 433 } |
| 434 | 434 |
| 435 void SafeBrowsingProtocolManager::ForceScheduleNextUpdate( | 435 void SafeBrowsingProtocolManager::ForceScheduleNextUpdate( |
| 436 const int next_update_msec) { | 436 base::TimeDelta interval) { |
| 437 DCHECK_GE(next_update_msec, 0); | 437 DCHECK(interval >= base::TimeDelta()); |
| 438 // Unschedule any current timer. | 438 // Unschedule any current timer. |
| 439 update_timer_.Stop(); | 439 update_timer_.Stop(); |
| 440 update_timer_.Start(FROM_HERE, TimeDelta::FromMilliseconds(next_update_msec), | 440 update_timer_.Start(FROM_HERE, interval, this, |
| 441 this, &SafeBrowsingProtocolManager::GetNextUpdate); | 441 &SafeBrowsingProtocolManager::GetNextUpdate); |
| 442 } | 442 } |
| 443 | 443 |
| 444 // According to section 5 of the SafeBrowsing protocol specification, we must | 444 // According to section 5 of the SafeBrowsing protocol specification, we must |
| 445 // back off after a certain number of errors. We only change 'next_update_sec_' | 445 // back off after a certain number of errors. We only change |next_update_sec_| |
| 446 // when we receive a response from the SafeBrowsing service. | 446 // when we receive a response from the SafeBrowsing service. |
| 447 int SafeBrowsingProtocolManager::GetNextUpdateTime(bool back_off) { | 447 base::TimeDelta SafeBrowsingProtocolManager::GetNextUpdateInterval( |
| 448 int next = next_update_sec_; | 448 bool back_off) { |
| 449 DCHECK(next_update_interval_ > base::TimeDelta()); |
| 450 base::TimeDelta next = next_update_interval_; |
| 449 if (back_off) { | 451 if (back_off) { |
| 450 next = GetNextBackOffTime(&update_error_count_, &update_back_off_mult_); | 452 next = GetNextBackOffInterval(&update_error_count_, &update_back_off_mult_); |
| 451 } else { | 453 } else { |
| 452 // Successful response means error reset. | 454 // Successful response means error reset. |
| 453 update_error_count_ = 0; | 455 update_error_count_ = 0; |
| 454 update_back_off_mult_ = 1; | 456 update_back_off_mult_ = 1; |
| 455 } | 457 } |
| 456 return next * 1000; // milliseconds | 458 return next; |
| 457 } | 459 } |
| 458 | 460 |
| 459 int SafeBrowsingProtocolManager::GetNextBackOffTime(int* error_count, | 461 base::TimeDelta SafeBrowsingProtocolManager::GetNextBackOffInterval( |
| 460 int* multiplier) { | 462 int* error_count, int* multiplier) const { |
| 461 DCHECK(multiplier && error_count); | 463 DCHECK(multiplier && error_count); |
| 462 (*error_count)++; | 464 (*error_count)++; |
| 463 if (*error_count > 1 && *error_count < 6) { | 465 if (*error_count > 1 && *error_count < 6) { |
| 464 int next = static_cast<int>(*multiplier * (1 + back_off_fuzz_) * 30 * 60); | 466 base::TimeDelta next = base::TimeDelta::FromMinutes( |
| 467 *multiplier * (1 + back_off_fuzz_) * 30); |
| 465 *multiplier *= 2; | 468 *multiplier *= 2; |
| 466 if (*multiplier > kSbMaxBackOff) | 469 if (*multiplier > kSbMaxBackOff) |
| 467 *multiplier = kSbMaxBackOff; | 470 *multiplier = kSbMaxBackOff; |
| 468 return next; | 471 return next; |
| 469 } | 472 } |
| 470 | |
| 471 if (*error_count >= 6) | 473 if (*error_count >= 6) |
| 472 return 60 * 60 * 8; // 8 hours | 474 return base::TimeDelta::FromHours(8); |
| 473 | 475 return base::TimeDelta::FromMinutes(1); |
| 474 return 60; // 1 minute | |
| 475 } | 476 } |
| 476 | 477 |
| 477 // This request requires getting a list of all the chunks for each list from the | 478 // This request requires getting a list of all the chunks for each list from the |
| 478 // database asynchronously. The request will be issued when we're called back in | 479 // database asynchronously. The request will be issued when we're called back in |
| 479 // OnGetChunksComplete. | 480 // OnGetChunksComplete. |
| 480 // TODO(paulg): We should get this at start up and maintain a ChunkRange cache | 481 // TODO(paulg): We should get this at start up and maintain a ChunkRange cache |
| 481 // to avoid hitting the database with each update request. On the | 482 // to avoid hitting the database with each update request. On the |
| 482 // otherhand, this request will only occur ~20-30 minutes so there | 483 // otherhand, this request will only occur ~20-30 minutes so there |
| 483 // isn't that much overhead. Measure! | 484 // isn't that much overhead. Measure! |
| 484 void SafeBrowsingProtocolManager::IssueUpdateRequest() { | 485 void SafeBrowsingProtocolManager::IssueUpdateRequest() { |
| (...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 623 } | 624 } |
| 624 if (!list.subs.empty()) { | 625 if (!list.subs.empty()) { |
| 625 formatted_results.append("s:" + list.subs); | 626 formatted_results.append("s:" + list.subs); |
| 626 } | 627 } |
| 627 formatted_results.append("\n"); | 628 formatted_results.append("\n"); |
| 628 | 629 |
| 629 return formatted_results; | 630 return formatted_results; |
| 630 } | 631 } |
| 631 | 632 |
| 632 void SafeBrowsingProtocolManager::HandleGetHashError(const Time& now) { | 633 void SafeBrowsingProtocolManager::HandleGetHashError(const Time& now) { |
| 633 int next = GetNextBackOffTime(&gethash_error_count_, &gethash_back_off_mult_); | 634 base::TimeDelta next = GetNextBackOffInterval( |
| 634 next_gethash_time_ = now + TimeDelta::FromSeconds(next); | 635 &gethash_error_count_, &gethash_back_off_mult_); |
| 636 next_gethash_time_ = now + next; |
| 635 } | 637 } |
| 636 | 638 |
| 637 void SafeBrowsingProtocolManager::UpdateFinished(bool success) { | 639 void SafeBrowsingProtocolManager::UpdateFinished(bool success) { |
| 638 UMA_HISTOGRAM_COUNTS("SB2.UpdateSize", update_size_); | 640 UMA_HISTOGRAM_COUNTS("SB2.UpdateSize", update_size_); |
| 639 update_size_ = 0; | 641 update_size_ = 0; |
| 640 sb_service_->UpdateFinished(success); | 642 sb_service_->UpdateFinished(success); |
| 641 } | 643 } |
| 642 | 644 |
| 643 std::string SafeBrowsingProtocolManager::ComposeUrl( | 645 std::string SafeBrowsingProtocolManager::ComposeUrl( |
| 644 const std::string& prefix, const std::string& method, | 646 const std::string& prefix, const std::string& method, |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 731 if (!additional_query_.empty()) { | 733 if (!additional_query_.empty()) { |
| 732 if (next_url.find("?") != std::string::npos) { | 734 if (next_url.find("?") != std::string::npos) { |
| 733 next_url.append("&"); | 735 next_url.append("&"); |
| 734 } else { | 736 } else { |
| 735 next_url.append("?"); | 737 next_url.append("?"); |
| 736 } | 738 } |
| 737 next_url.append(additional_query_); | 739 next_url.append(additional_query_); |
| 738 } | 740 } |
| 739 return GURL(next_url); | 741 return GURL(next_url); |
| 740 } | 742 } |
| OLD | NEW |