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 |