url_request_throttler_manager.cc 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  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. #include "net/url_request/url_request_throttler_manager.h"
  5. #include "base/check_op.h"
  6. #include "base/strings/string_util.h"
  7. #include "net/base/url_util.h"
  8. #include "net/log/net_log.h"
  9. #include "net/log/net_log_event_type.h"
  10. #include "net/log/net_log_source_type.h"
  11. namespace net {
  12. const unsigned int URLRequestThrottlerManager::kMaximumNumberOfEntries = 1500;
  13. const unsigned int URLRequestThrottlerManager::kRequestsBetweenCollecting = 200;
  14. URLRequestThrottlerManager::URLRequestThrottlerManager() {
  15. url_id_replacements_.ClearPassword();
  16. url_id_replacements_.ClearUsername();
  17. url_id_replacements_.ClearQuery();
  18. url_id_replacements_.ClearRef();
  19. NetworkChangeNotifier::AddIPAddressObserver(this);
  20. NetworkChangeNotifier::AddConnectionTypeObserver(this);
  21. }
  22. URLRequestThrottlerManager::~URLRequestThrottlerManager() {
  23. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  24. NetworkChangeNotifier::RemoveIPAddressObserver(this);
  25. NetworkChangeNotifier::RemoveConnectionTypeObserver(this);
  26. // Since the manager object might conceivably go away before the
  27. // entries, detach the entries' back-pointer to the manager.
  28. auto i = url_entries_.begin();
  29. while (i != url_entries_.end()) {
  30. if (i->second.get() != nullptr) {
  31. i->second->DetachManager();
  32. }
  33. ++i;
  34. }
  35. // Delete all entries.
  36. url_entries_.clear();
  37. }
  38. scoped_refptr<URLRequestThrottlerEntryInterface>
  39. URLRequestThrottlerManager::RegisterRequestUrl(const GURL &url) {
  40. DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  41. // Normalize the url.
  42. std::string url_id = GetIdFromUrl(url);
  43. // Periodically garbage collect old entries.
  44. GarbageCollectEntriesIfNecessary();
  45. // Find the entry in the map or create a new NULL entry.
  46. scoped_refptr<URLRequestThrottlerEntry>& entry = url_entries_[url_id];
  47. // If the entry exists but could be garbage collected at this point, we
  48. // start with a fresh entry so that we possibly back off a bit less
  49. // aggressively (i.e. this resets the error count when the entry's URL
  50. // hasn't been requested in long enough).
  51. if (entry.get() && entry->IsEntryOutdated()) {
  52. entry = nullptr;
  53. }
  54. // Create the entry if needed.
  55. if (entry.get() == nullptr) {
  56. entry = base::MakeRefCounted<URLRequestThrottlerEntry>(this, url_id);
  57. // We only disable back-off throttling on an entry that we have
  58. // just constructed. This is to allow unit tests to explicitly override
  59. // the entry for localhost URLs.
  60. if (IsLocalhost(url)) {
  61. if (!logged_for_localhost_disabled_ && IsLocalhost(url)) {
  62. logged_for_localhost_disabled_ = true;
  63. net_log_.AddEventWithStringParams(
  64. NetLogEventType::THROTTLING_DISABLED_FOR_HOST, "host", url.host());
  65. }
  66. // TODO(joi): Once sliding window is separate from back-off throttling,
  67. // we can simply return a dummy implementation of
  68. // URLRequestThrottlerEntryInterface here that never blocks anything.
  69. entry->DisableBackoffThrottling();
  70. }
  71. }
  72. return entry;
  73. }
  74. void URLRequestThrottlerManager::OverrideEntryForTests(
  75. const GURL& url,
  76. scoped_refptr<URLRequestThrottlerEntry> entry) {
  77. // Normalize the url.
  78. std::string url_id = GetIdFromUrl(url);
  79. // Periodically garbage collect old entries.
  80. GarbageCollectEntriesIfNecessary();
  81. url_entries_[url_id] = std::move(entry);
  82. }
  83. void URLRequestThrottlerManager::EraseEntryForTests(const GURL& url) {
  84. // Normalize the url.
  85. std::string url_id = GetIdFromUrl(url);
  86. url_entries_.erase(url_id);
  87. }
  88. void URLRequestThrottlerManager::set_net_log(NetLog* net_log) {
  89. DCHECK(net_log);
  90. net_log_ = NetLogWithSource::Make(
  91. net_log, NetLogSourceType::EXPONENTIAL_BACKOFF_THROTTLING);
  92. }
  93. NetLog* URLRequestThrottlerManager::net_log() const {
  94. return net_log_.net_log();
  95. }
  96. void URLRequestThrottlerManager::OnIPAddressChanged() {
  97. OnNetworkChange();
  98. }
  99. void URLRequestThrottlerManager::OnConnectionTypeChanged(
  100. NetworkChangeNotifier::ConnectionType type) {
  101. OnNetworkChange();
  102. }
  103. std::string URLRequestThrottlerManager::GetIdFromUrl(const GURL& url) const {
  104. if (!url.is_valid())
  105. return url.possibly_invalid_spec();
  106. GURL id = url.ReplaceComponents(url_id_replacements_);
  107. return base::ToLowerASCII(id.spec());
  108. }
  109. void URLRequestThrottlerManager::GarbageCollectEntriesIfNecessary() {
  110. requests_since_last_gc_++;
  111. if (requests_since_last_gc_ < kRequestsBetweenCollecting)
  112. return;
  113. requests_since_last_gc_ = 0;
  114. GarbageCollectEntries();
  115. }
  116. void URLRequestThrottlerManager::GarbageCollectEntries() {
  117. auto i = url_entries_.begin();
  118. while (i != url_entries_.end()) {
  119. if ((i->second)->IsEntryOutdated()) {
  120. url_entries_.erase(i++);
  121. } else {
  122. ++i;
  123. }
  124. }
  125. // In case something broke we want to make sure not to grow indefinitely.
  126. while (url_entries_.size() > kMaximumNumberOfEntries) {
  127. url_entries_.erase(url_entries_.begin());
  128. }
  129. }
  130. void URLRequestThrottlerManager::OnNetworkChange() {
  131. // Remove all entries. Any entries that in-flight requests have a reference
  132. // to will live until those requests end, and these entries may be
  133. // inconsistent with new entries for the same URLs, but since what we
  134. // want is a clean slate for the new connection type, this is OK.
  135. url_entries_.clear();
  136. requests_since_last_gc_ = 0;
  137. }
  138. } // namespace net