Chromium Code Reviews| 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 #include <utility> | 7 #include <utility> |
| 8 | 8 |
| 9 #include "base/base64.h" | 9 #include "base/base64.h" |
| 10 #include "base/environment.h" | 10 #include "base/environment.h" |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 134 } | 134 } |
| 135 | 135 |
| 136 SafeBrowsingProtocolManager::SafeBrowsingProtocolManager( | 136 SafeBrowsingProtocolManager::SafeBrowsingProtocolManager( |
| 137 SafeBrowsingProtocolManagerDelegate* delegate, | 137 SafeBrowsingProtocolManagerDelegate* delegate, |
| 138 net::URLRequestContextGetter* request_context_getter, | 138 net::URLRequestContextGetter* request_context_getter, |
| 139 const SafeBrowsingProtocolConfig& config) | 139 const SafeBrowsingProtocolConfig& config) |
| 140 : delegate_(delegate), | 140 : delegate_(delegate), |
| 141 request_type_(NO_REQUEST), | 141 request_type_(NO_REQUEST), |
| 142 update_error_count_(0), | 142 update_error_count_(0), |
| 143 gethash_error_count_(0), | 143 gethash_error_count_(0), |
| 144 gethash_v4_error_count_(0), | |
| 144 update_back_off_mult_(1), | 145 update_back_off_mult_(1), |
| 145 gethash_back_off_mult_(1), | 146 gethash_back_off_mult_(1), |
| 147 gethash_v4_back_off_mult_(1), | |
| 146 next_update_interval_(base::TimeDelta::FromSeconds( | 148 next_update_interval_(base::TimeDelta::FromSeconds( |
| 147 base::RandInt(kSbTimerStartIntervalSecMin, | 149 base::RandInt(kSbTimerStartIntervalSecMin, |
| 148 kSbTimerStartIntervalSecMax))), | 150 kSbTimerStartIntervalSecMax))), |
| 149 chunk_pending_to_write_(false), | 151 chunk_pending_to_write_(false), |
| 152 next_gethash_v4_time_(Time::Now()), | |
| 150 version_(config.version), | 153 version_(config.version), |
| 151 update_size_(0), | 154 update_size_(0), |
| 152 client_name_(config.client_name), | 155 client_name_(config.client_name), |
| 153 request_context_getter_(request_context_getter), | 156 request_context_getter_(request_context_getter), |
| 154 url_prefix_(config.url_prefix), | 157 url_prefix_(config.url_prefix), |
| 155 backup_update_reason_(BACKUP_UPDATE_REASON_MAX), | 158 backup_update_reason_(BACKUP_UPDATE_REASON_MAX), |
| 156 disable_auto_update_(config.disable_auto_update), | 159 disable_auto_update_(config.disable_auto_update), |
| 157 url_fetcher_id_(0), | 160 url_fetcher_id_(0), |
| 158 app_in_foreground_(true) { | 161 app_in_foreground_(true) { |
| 159 DCHECK(!url_prefix_.empty()); | 162 DCHECK(!url_prefix_.empty()); |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 273 | 276 |
| 274 if (!response.ParseFromString(data)) | 277 if (!response.ParseFromString(data)) |
| 275 return false; | 278 return false; |
| 276 | 279 |
| 277 if (response.has_negative_cache_duration()) { | 280 if (response.has_negative_cache_duration()) { |
| 278 // Seconds resolution is good enough so we ignore the nanos field. | 281 // Seconds resolution is good enough so we ignore the nanos field. |
| 279 *negative_cache_duration = base::TimeDelta::FromSeconds( | 282 *negative_cache_duration = base::TimeDelta::FromSeconds( |
| 280 response.negative_cache_duration().seconds()); | 283 response.negative_cache_duration().seconds()); |
| 281 } | 284 } |
| 282 | 285 |
| 286 if (response.has_minimum_wait_duration()) { | |
| 287 // Seconds resolution is good enough so we ignore the nanos field. | |
| 288 next_gethash_v4_time_ = Time::Now() + base::TimeDelta::FromSeconds( | |
| 289 response.minimum_wait_duration().seconds()); | |
| 290 } | |
| 291 | |
| 283 // Loop over the threat matches and fill in full_hashes. | 292 // Loop over the threat matches and fill in full_hashes. |
| 284 for (const ThreatMatch& match : response.matches()) { | 293 for (const ThreatMatch& match : response.matches()) { |
| 285 // Make sure the platform and threat entry type match. | 294 // Make sure the platform and threat entry type match. |
| 286 if (!(match.has_threat_entry_type() && | 295 if (!(match.has_threat_entry_type() && |
| 287 match.threat_entry_type() == URL_EXPRESSION && | 296 match.threat_entry_type() == URL_EXPRESSION && |
| 288 match.has_threat())) { | 297 match.has_threat())) { |
| 289 continue; | 298 continue; |
| 290 } | 299 } |
| 291 | 300 |
| 292 // Fill in the full hash. | 301 // Fill in the full hash. |
| (...skipping 24 matching lines...) Expand all Loading... | |
| 317 } | 326 } |
| 318 return true; | 327 return true; |
| 319 } | 328 } |
| 320 | 329 |
| 321 void SafeBrowsingProtocolManager::GetV4FullHashes( | 330 void SafeBrowsingProtocolManager::GetV4FullHashes( |
| 322 const std::vector<SBPrefix>& prefixes, | 331 const std::vector<SBPrefix>& prefixes, |
| 323 const std::vector<PlatformType>& platforms, | 332 const std::vector<PlatformType>& platforms, |
| 324 ThreatType threat_type, | 333 ThreatType threat_type, |
| 325 FullHashCallback callback) { | 334 FullHashCallback callback) { |
| 326 DCHECK(CalledOnValidThread()); | 335 DCHECK(CalledOnValidThread()); |
| 327 // TODO(kcarattini): Implement backoff behavior. | 336 // We need to wait the minimum waiting duration, and if we are in backoff, |
| 337 // we need to check if we're past the next allowed time. If we are, we can | |
| 338 // proceed with the request. If not, we are required to return empty results | |
| 339 // (i.e. treat the page as safe). | |
| 340 if (Time::Now() <= next_gethash_v4_time_) { | |
| 341 // TODO(kcarattini): Add UMA recording. | |
| 342 std::vector<SBFullHashResult> full_hashes; | |
| 343 callback.Run(full_hashes, base::TimeDelta()); | |
| 344 return; | |
| 345 } | |
| 328 | 346 |
| 329 std::string req_base64 = GetV4HashRequest(prefixes, platforms, threat_type); | 347 std::string req_base64 = GetV4HashRequest(prefixes, platforms, threat_type); |
| 330 GURL gethash_url = GetV4HashUrl(req_base64); | 348 GURL gethash_url = GetV4HashUrl(req_base64); |
| 331 | 349 |
| 332 net::URLFetcher* fetcher = | 350 net::URLFetcher* fetcher = |
| 333 net::URLFetcher::Create(url_fetcher_id_++, gethash_url, | 351 net::URLFetcher::Create(url_fetcher_id_++, gethash_url, |
| 334 net::URLFetcher::GET, this) | 352 net::URLFetcher::GET, this) |
| 335 .release(); | 353 .release(); |
| 336 v4_hash_requests_[fetcher] = FullHashDetails(callback, | 354 v4_hash_requests_[fetcher] = FullHashDetails(callback, |
| 337 false /* is_download */); | 355 false /* is_download */); |
| (...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 424 | 442 |
| 425 hash_requests_.erase(it); | 443 hash_requests_.erase(it); |
| 426 } else if (v4_it != v4_hash_requests_.end()) { | 444 } else if (v4_it != v4_hash_requests_.end()) { |
| 427 // V4 FindFullHashes response. | 445 // V4 FindFullHashes response. |
| 428 fetcher.reset(v4_it->first); | 446 fetcher.reset(v4_it->first); |
| 429 const FullHashDetails& details = v4_it->second; | 447 const FullHashDetails& details = v4_it->second; |
| 430 std::vector<SBFullHashResult> full_hashes; | 448 std::vector<SBFullHashResult> full_hashes; |
| 431 base::TimeDelta negative_cache_duration; | 449 base::TimeDelta negative_cache_duration; |
| 432 if (status.is_success() && response_code == net::HTTP_OK) { | 450 if (status.is_success() && response_code == net::HTTP_OK) { |
| 433 // TODO(kcarattini): Add UMA reporting. | 451 // TODO(kcarattini): Add UMA reporting. |
| 434 // TODO(kcarattini): Implement backoff and minimum waiting duration | 452 gethash_v4_error_count_ = 0; |
| 435 // compliance. | 453 gethash_v4_back_off_mult_ = 1; |
| 436 std::string data; | 454 std::string data; |
| 437 source->GetResponseAsString(&data); | 455 source->GetResponseAsString(&data); |
| 438 if (!ParseV4HashResponse(data, &full_hashes, &negative_cache_duration)) { | 456 if (!ParseV4HashResponse(data, &full_hashes, &negative_cache_duration)) { |
| 439 full_hashes.clear(); | 457 full_hashes.clear(); |
| 440 // TODO(kcarattini): Add UMA reporting. | 458 // TODO(kcarattini): Add UMA reporting. |
| 441 } | 459 } |
| 442 } else { | 460 } else { |
| 443 // TODO(kcarattini): Handle error by setting backoff interval. | 461 HandleGetHashV4Error(Time::Now()); |
| 444 // TODO(kcarattini): Add UMA reporting. | 462 // TODO(kcarattini): Add UMA reporting. |
| 445 if (status.status() == net::URLRequestStatus::FAILED) { | 463 if (status.status() == net::URLRequestStatus::FAILED) { |
| 446 DVLOG(1) << "SafeBrowsing GetEncodedFullHashes request for: " << | 464 DVLOG(1) << "SafeBrowsing GetEncodedFullHashes request for: " << |
| 447 source->GetURL() << " failed with error: " << status.error(); | 465 source->GetURL() << " failed with error: " << status.error(); |
| 448 } else { | 466 } else { |
| 449 DVLOG(1) << "SafeBrowsing GetEncodedFullHashes request for: " << | 467 DVLOG(1) << "SafeBrowsing GetEncodedFullHashes request for: " << |
| 450 source->GetURL() << " failed with error: " << response_code; | 468 source->GetURL() << " failed with error: " << response_code; |
| 451 } | 469 } |
| 452 } | 470 } |
| 453 | 471 |
| (...skipping 249 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 703 *multiplier *= 2; | 721 *multiplier *= 2; |
| 704 if (*multiplier > kSbMaxBackOff) | 722 if (*multiplier > kSbMaxBackOff) |
| 705 *multiplier = kSbMaxBackOff; | 723 *multiplier = kSbMaxBackOff; |
| 706 return next; | 724 return next; |
| 707 } | 725 } |
| 708 if (*error_count >= 6) | 726 if (*error_count >= 6) |
| 709 return base::TimeDelta::FromHours(8); | 727 return base::TimeDelta::FromHours(8); |
| 710 return base::TimeDelta::FromMinutes(1); | 728 return base::TimeDelta::FromMinutes(1); |
| 711 } | 729 } |
| 712 | 730 |
| 731 // Backoff interval is MIN(((2^(n-1))*15 minutes) * (RAND + 1), 24 hours) where | |
| 732 // n is the number of consecutive errors. | |
| 733 base::TimeDelta SafeBrowsingProtocolManager::GetNextV4BackOffInterval( | |
|
Nathan Parker
2016/01/07 06:06:58
This could be static, if you remove the CalledOnVa
kcarattini
2016/01/07 06:48:53
Done.
| |
| 734 size_t* error_count, | |
| 735 size_t* multiplier) const { | |
| 736 DCHECK(CalledOnValidThread()); | |
| 737 DCHECK(multiplier && error_count); | |
| 738 (*error_count)++; | |
| 739 if (*error_count > 1) { | |
| 740 *multiplier *= 2; | |
|
Nathan Parker
2016/01/07 06:06:58
What happens on integer overflow? Probably want t
kcarattini
2016/01/07 06:48:53
Done.
| |
| 741 } | |
| 742 base::TimeDelta next = base::TimeDelta::FromMinutes( | |
| 743 *multiplier * (1 + base::RandDouble()) * 15); | |
| 744 | |
| 745 base::TimeDelta day = base::TimeDelta::FromHours(24); | |
| 746 | |
| 747 if (next < day) | |
| 748 return next; | |
| 749 else | |
| 750 return day; | |
| 751 } | |
| 752 | |
| 713 // This request requires getting a list of all the chunks for each list from the | 753 // This request requires getting a list of all the chunks for each list from the |
| 714 // database asynchronously. The request will be issued when we're called back in | 754 // database asynchronously. The request will be issued when we're called back in |
| 715 // OnGetChunksComplete. | 755 // OnGetChunksComplete. |
| 716 // TODO(paulg): We should get this at start up and maintain a ChunkRange cache | 756 // TODO(paulg): We should get this at start up and maintain a ChunkRange cache |
| 717 // to avoid hitting the database with each update request. On the | 757 // to avoid hitting the database with each update request. On the |
| 718 // otherhand, this request will only occur ~20-30 minutes so there | 758 // otherhand, this request will only occur ~20-30 minutes so there |
| 719 // isn't that much overhead. Measure! | 759 // isn't that much overhead. Measure! |
| 720 void SafeBrowsingProtocolManager::IssueUpdateRequest() { | 760 void SafeBrowsingProtocolManager::IssueUpdateRequest() { |
| 721 DCHECK(CalledOnValidThread()); | 761 DCHECK(CalledOnValidThread()); |
| 722 request_type_ = UPDATE_REQUEST; | 762 request_type_ = UPDATE_REQUEST; |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 857 } | 897 } |
| 858 } | 898 } |
| 859 | 899 |
| 860 void SafeBrowsingProtocolManager::HandleGetHashError(const Time& now) { | 900 void SafeBrowsingProtocolManager::HandleGetHashError(const Time& now) { |
| 861 DCHECK(CalledOnValidThread()); | 901 DCHECK(CalledOnValidThread()); |
| 862 base::TimeDelta next = | 902 base::TimeDelta next = |
| 863 GetNextBackOffInterval(&gethash_error_count_, &gethash_back_off_mult_); | 903 GetNextBackOffInterval(&gethash_error_count_, &gethash_back_off_mult_); |
| 864 next_gethash_time_ = now + next; | 904 next_gethash_time_ = now + next; |
| 865 } | 905 } |
| 866 | 906 |
| 907 void SafeBrowsingProtocolManager::HandleGetHashV4Error(const Time& now) { | |
| 908 DCHECK(CalledOnValidThread()); | |
| 909 base::TimeDelta next = GetNextV4BackOffInterval( | |
| 910 &gethash_v4_error_count_, &gethash_v4_back_off_mult_); | |
| 911 next_gethash_v4_time_ = now + next; | |
| 912 } | |
| 913 | |
| 867 void SafeBrowsingProtocolManager::UpdateFinished(bool success) { | 914 void SafeBrowsingProtocolManager::UpdateFinished(bool success) { |
| 868 UpdateFinished(success, !success); | 915 UpdateFinished(success, !success); |
| 869 } | 916 } |
| 870 | 917 |
| 871 void SafeBrowsingProtocolManager::UpdateFinished(bool success, bool back_off) { | 918 void SafeBrowsingProtocolManager::UpdateFinished(bool success, bool back_off) { |
| 872 DCHECK(CalledOnValidThread()); | 919 DCHECK(CalledOnValidThread()); |
| 873 UMA_HISTOGRAM_COUNTS("SB2.UpdateSize", update_size_); | 920 UMA_HISTOGRAM_COUNTS("SB2.UpdateSize", update_size_); |
| 874 update_size_ = 0; | 921 update_size_ = 0; |
| 875 bool update_success = success || request_type_ == CHUNK_REQUEST; | 922 bool update_success = success || request_type_ == CHUNK_REQUEST; |
| 876 if (backup_update_reason_ == BACKUP_UPDATE_REASON_MAX) { | 923 if (backup_update_reason_ == BACKUP_UPDATE_REASON_MAX) { |
| (...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 956 SafeBrowsingProtocolManager::FullHashDetails::FullHashDetails( | 1003 SafeBrowsingProtocolManager::FullHashDetails::FullHashDetails( |
| 957 FullHashCallback callback, | 1004 FullHashCallback callback, |
| 958 bool is_download) | 1005 bool is_download) |
| 959 : callback(callback), is_download(is_download) {} | 1006 : callback(callback), is_download(is_download) {} |
| 960 | 1007 |
| 961 SafeBrowsingProtocolManager::FullHashDetails::~FullHashDetails() {} | 1008 SafeBrowsingProtocolManager::FullHashDetails::~FullHashDetails() {} |
| 962 | 1009 |
| 963 SafeBrowsingProtocolManagerDelegate::~SafeBrowsingProtocolManagerDelegate() {} | 1010 SafeBrowsingProtocolManagerDelegate::~SafeBrowsingProtocolManagerDelegate() {} |
| 964 | 1011 |
| 965 } // namespace safe_browsing | 1012 } // namespace safe_browsing |
| OLD | NEW |