diff options
author | joi@chromium.org <joi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-17 18:59:52 +0000 |
---|---|---|
committer | joi@chromium.org <joi@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-08-17 18:59:52 +0000 |
commit | 99c07901d1acfbe9d206d28fb930de7dfe3b973a (patch) | |
tree | 6acca5d693acb0286a41689ed065aa204e9273ef /net | |
parent | 762535c0ba0a758becfb4903c88716bbc56c6d18 (diff) | |
download | chromium_src-99c07901d1acfbe9d206d28fb930de7dfe3b973a.zip chromium_src-99c07901d1acfbe9d206d28fb930de7dfe3b973a.tar.gz chromium_src-99c07901d1acfbe9d206d28fb930de7dfe3b973a.tar.bz2 |
Revert 56376 - This CL will introduce a new way to do exponential back-off on failure within
Chromium. It is a network level implementation and should constitute a good
enough bottleneck to manage every outgoing http request.
Committing for malavv@google.com.
Original review: http://codereview.chromium.org/2487001/show
R=phajdan-jr
BUG=none
TEST=unit tests
Review URL: http://codereview.chromium.org/3005049
TBR=joi@chromium.org
Review URL: http://codereview.chromium.org/3165029
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@56393 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net')
-rw-r--r-- | net/base/net_error_list.h | 4 | ||||
-rw-r--r-- | net/net.gyp | 9 | ||||
-rw-r--r-- | net/request_throttler/request_throttler_entry.cc | 134 | ||||
-rw-r--r-- | net/request_throttler/request_throttler_entry.h | 104 | ||||
-rw-r--r-- | net/request_throttler/request_throttler_entry_interface.h | 33 | ||||
-rw-r--r-- | net/request_throttler/request_throttler_header_adapter.cc | 21 | ||||
-rw-r--r-- | net/request_throttler/request_throttler_header_adapter.h | 32 | ||||
-rw-r--r-- | net/request_throttler/request_throttler_header_interface.h | 24 | ||||
-rw-r--r-- | net/request_throttler/request_throttler_manager.cc | 85 | ||||
-rw-r--r-- | net/request_throttler/request_throttler_manager.h | 79 | ||||
-rw-r--r-- | net/request_throttler/request_throttler_unittest.cc | 302 | ||||
-rw-r--r-- | net/url_request/url_request_http_job.cc | 33 | ||||
-rw-r--r-- | net/url_request/url_request_http_job.h | 5 |
13 files changed, 9 insertions, 856 deletions
diff --git a/net/base/net_error_list.h b/net/base/net_error_list.h index a626fad..5fe0846 100644 --- a/net/base/net_error_list.h +++ b/net/base/net_error_list.h @@ -171,10 +171,6 @@ NET_ERROR(SSL_UNSAFE_NEGOTIATION, -128) // The SSL server is using a weak cryptographic key. NET_ERROR(SSL_WEAK_SERVER_KEY, -129) -// The request throttler module cancelled this request because the are too many -// requests to a server that is failing requests. -NET_ERROR(TEMPORARILY_THROTTLED_BY_DDOS, -130) - // Certificate error codes // // The values of certificate error codes must be consecutive. diff --git a/net/net.gyp b/net/net.gyp index e02ebf4..abbbc74 100644 --- a/net/net.gyp +++ b/net/net.gyp @@ -466,14 +466,6 @@ 'proxy/proxy_service.h', 'proxy/sync_host_resolver_bridge.cc', 'proxy/sync_host_resolver_bridge.h', - 'request_throttler/request_throttler_entry.cc', - 'request_throttler/request_throttler_entry.h', - 'request_throttler/request_throttler_entry_interface.h', - 'request_throttler/request_throttler_header_adapter.h', - 'request_throttler/request_throttler_header_adapter.cc', - 'request_throttler/request_throttler_header_interface.h', - 'request_throttler/request_throttler_manager.cc', - 'request_throttler/request_throttler_manager.h', 'socket/client_socket.cc', 'socket/client_socket.h', 'socket/client_socket_factory.cc', @@ -784,7 +776,6 @@ 'proxy/proxy_server_unittest.cc', 'proxy/proxy_service_unittest.cc', 'proxy/sync_host_resolver_bridge_unittest.cc', - 'request_throttler/request_throttler_unittest.cc', 'socket/client_socket_pool_base_unittest.cc', 'socket/socks5_client_socket_unittest.cc', 'socket/socks_client_socket_pool_unittest.cc', diff --git a/net/request_throttler/request_throttler_entry.cc b/net/request_throttler/request_throttler_entry.cc deleted file mode 100644 index 826358d..0000000 --- a/net/request_throttler/request_throttler_entry.cc +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/request_throttler/request_throttler_entry.h" - -#include <cmath> - -#include "base/logging.h" -#include "base/rand_util.h" -#include "base/string_number_conversions.h" -#include "base/string_util.h" -#include "net/request_throttler/request_throttler_header_interface.h" - -const int RequestThrottlerEntry::kAdditionalConstantMs = 100; -const int RequestThrottlerEntry::kEntryLifetimeSec = 120; -const double RequestThrottlerEntry::kJitterFactor = 0.4; -const int RequestThrottlerEntry::kInitialBackoffMs = 700; -const int RequestThrottlerEntry::kMaximumBackoffMs = 24 * 60 * 60 * 1000; -const double RequestThrottlerEntry::kMultiplyFactor = 2.0; -const char RequestThrottlerEntry::kRetryHeaderName[] = "X-Retry-After"; - -RequestThrottlerEntry::RequestThrottlerEntry() - : release_time_(base::TimeTicks::Now()), - num_times_delayed_(0), - is_managed_(false) { - SaveState(); -} - -RequestThrottlerEntry::~RequestThrottlerEntry() { -} - -bool RequestThrottlerEntry::IsRequestAllowed() const { - return (release_time_ <= GetTimeNow()); -} - -void RequestThrottlerEntry::UpdateWithResponse( - const RequestThrottlerHeaderInterface* response) { - SaveState(); - if (response->GetResponseCode() >= 500) { - num_times_delayed_++; - release_time_ = std::max(CalculateReleaseTime(), release_time_); - is_managed_ = true; - } else { - // We slowly decay the number of times delayed instead of resetting it to 0 - // in order to stay stable if we received lots of requests with - // malformed bodies at the same time. - if (num_times_delayed_ > 0) - num_times_delayed_--; - is_managed_ = false; - // The reason why we are not just cutting release_time to GetTimeNow() is - // on the one hand, it would unset delay put by our custom retry-after - // header and on the other we would like to push every request up to our - // "horizon" when dealing with multiple in-flight request. Ex: If we send - // three request and we receive 2 failures and 1 success. The success that - // follows those failures will not reset release time further request will - // then need to wait the delay caused by the 2 failures. - release_time_ = std::max(GetTimeNow(), release_time_); - if (response->GetNormalizedValue(kRetryHeaderName) != std::string()) - HandleCustomRetryAfter(response->GetNormalizedValue(kRetryHeaderName)); - } -} - -bool RequestThrottlerEntry::IsEntryOutdated() const { - int64 unused_since_ms = (GetTimeNow() - release_time_).InMilliseconds(); - int64 lifespan_ms = kEntryLifetimeSec * 1000; - - // Release time is further than now, we are managing it. - if (unused_since_ms < 0) - return false; - - // There are two cases. First one, when the entry is currently being managed - // and should not be collected unless it is older than the maximum allowed - // back-off. The other one, when the entry is outdated, unmanaged and should - // be collected. - if (is_managed_) - return unused_since_ms > kMaximumBackoffMs; - - return unused_since_ms > lifespan_ms; -} - -void RequestThrottlerEntry::ReceivedContentWasMalformed() { - // We should never revert to less back-off or else an attacker could put a - // malformed body in cache and replay it to decrease delay. - num_times_delayed_ = - std::max(old_values_.number_of_failed_requests, num_times_delayed_); - num_times_delayed_++; - is_managed_ = true; - release_time_ = std::max(CalculateReleaseTime(), - std::max(old_values_.release_time, release_time_)); -} - -base::TimeTicks RequestThrottlerEntry::CalculateReleaseTime() { - double delay = kInitialBackoffMs; - delay *= pow(kMultiplyFactor, num_times_delayed_); - delay += kAdditionalConstantMs; - delay -= base::RandDouble() * kJitterFactor * delay; - - // Ensure that we do not exceed maximum delay - int64 delay_int = static_cast<int64>(delay + 0.5); - delay_int = std::min(delay_int, static_cast<int64>(kMaximumBackoffMs)); - - return GetTimeNow() + base::TimeDelta::FromMilliseconds(delay_int); -} - -base::TimeTicks RequestThrottlerEntry::GetTimeNow() const { - return base::TimeTicks::Now(); -} - -void RequestThrottlerEntry::HandleCustomRetryAfter( - const std::string& header_value) { - // Input parameter is the number of seconds to wait in a floating point value. - double time_in_sec = 0; - bool conversion_is_ok = base::StringToDouble(header_value, &time_in_sec); - - // Conversion of custom retry-after header value failed. - if (!conversion_is_ok) - return; - - // We must use an int value later so we transform this in milliseconds. - int64 value_ms = static_cast<int64>(0.5 + time_in_sec * 1000); - - if (kMaximumBackoffMs < value_ms || value_ms < 0) - return; - - release_time_ = std::max( - (GetTimeNow() + base::TimeDelta::FromMilliseconds(value_ms)), - release_time_); -} - -void RequestThrottlerEntry::SaveState() { - old_values_.release_time = release_time_; - old_values_.number_of_failed_requests = num_times_delayed_; -} diff --git a/net/request_throttler/request_throttler_entry.h b/net/request_throttler/request_throttler_entry.h deleted file mode 100644 index cf8a4ae..0000000 --- a/net/request_throttler/request_throttler_entry.h +++ /dev/null @@ -1,104 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_REQUEST_THROTTLER_REQUEST_THROTTLER_ENTRY_H_ -#define NET_REQUEST_THROTTLER_REQUEST_THROTTLER_ENTRY_H_ - -#include "net/request_throttler/request_throttler_entry_interface.h" - -#include <string> - -#include "base/ref_counted.h" -#include "base/time.h" - -// Represents an entry of the Request Throttler Manager. -class RequestThrottlerEntry : public RequestThrottlerEntryInterface { - public: - // Additional constant to adjust back-off. - static const int kAdditionalConstantMs; - - // Time after which the entry is considered outdated. - static const int kEntryLifetimeSec; - - // Fuzzing percentage. ex: 10% will spread requests randomly - // between 90%-100% of the calculated time. - static const double kJitterFactor; - - // Initial delay. - static const int kInitialBackoffMs; - - // Maximum amount of time we are willing to delay our request. - static const int kMaximumBackoffMs; - - // Factor by which the waiting time will be multiplied. - static const double kMultiplyFactor; - - // Name of the header that servers can use to ask clients to delay their next - // request. ex: "X-Retry-After" - static const char kRetryHeaderName[]; - - RequestThrottlerEntry(); - - ////// Implementation of the Request throttler Interface. /////// - - // This method needs to be called prior to every request; if it returns - // false, the calling module must cancel its current request. - virtual bool IsRequestAllowed() const; - - // This method needs to be called each time a response is received. - virtual void UpdateWithResponse( - const RequestThrottlerHeaderInterface* response); - - ////////// Specific method of Request throttler Entry //////////////// - - // Used by the manager, returns if the entry needs to be garbage collected. - bool IsEntryOutdated() const; - - // Used by the manager, enables the manager to flag the last successful - // request as a failure. - void ReceivedContentWasMalformed(); - - protected: - - // This struct is used to save the state of the entry each time we are updated - // with a response header so we can regenerate it if we are informed that one - // of our bodies was malformed. - struct OldValues { - base::TimeTicks release_time; - int number_of_failed_requests; - }; - - virtual ~RequestThrottlerEntry(); - - // Calculates when we should start sending requests again. Follows a failure - // response. - base::TimeTicks CalculateReleaseTime(); - - // Equivalent to TimeTicks::Now(), virtual to be mockable for testing purpose. - virtual base::TimeTicks GetTimeNow() const; - - // Is used internally to increase release time following a retry-after header. - void HandleCustomRetryAfter(const std::string& header_value); - - // Saves the state of the object to be able to regenerate it. - // Must be informed of the state of the response. - void SaveState(); - - // This contains the timestamp at which we are allowed to start sending - // requests again. - base::TimeTicks release_time_; - - // Number of times we were delayed. - int num_times_delayed_; - - // Are we currently managing this request. - bool is_managed_; - - OldValues old_values_; - - private: - DISALLOW_COPY_AND_ASSIGN(RequestThrottlerEntry); -}; - -#endif // NET_REQUEST_THROTTLER_REQUEST_THROTTLER_ENTRY_H_ diff --git a/net/request_throttler/request_throttler_entry_interface.h b/net/request_throttler/request_throttler_entry_interface.h deleted file mode 100644 index 5781e54..0000000 --- a/net/request_throttler/request_throttler_entry_interface.h +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_REQUEST_THROTTLER_REQUEST_THROTTLER_ENTRY_INTERFACE_H_ -#define NET_REQUEST_THROTTLER_REQUEST_THROTTLER_ENTRY_INTERFACE_H_ - -#include "base/basictypes.h" -#include "base/ref_counted.h" - -class RequestThrottlerHeaderInterface; - -// Represents an entry of the request throttler manager. -class RequestThrottlerEntryInterface - : public base::RefCounted<RequestThrottlerEntryInterface> { - public: - RequestThrottlerEntryInterface() {} - - // This method needs to be called prior to every requests; if it returns - // false, the calling module must cancel its current request. - virtual bool IsRequestAllowed() const = 0; - - // This method needs to be called each time a response is received. - virtual void UpdateWithResponse( - const RequestThrottlerHeaderInterface* response) = 0; - protected: - virtual ~RequestThrottlerEntryInterface() {} - private: - friend class base::RefCounted<RequestThrottlerEntryInterface>; - DISALLOW_COPY_AND_ASSIGN(RequestThrottlerEntryInterface); -}; - -#endif // NET_REQUEST_THROTTLER_REQUEST_THROTTLER_ENTRY_INTERFACE_H_ diff --git a/net/request_throttler/request_throttler_header_adapter.cc b/net/request_throttler/request_throttler_header_adapter.cc deleted file mode 100644 index 5307044..0000000 --- a/net/request_throttler/request_throttler_header_adapter.cc +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/request_throttler/request_throttler_header_adapter.h" - -RequestThrottlerHeaderAdapter::RequestThrottlerHeaderAdapter( - const scoped_refptr<net::HttpResponseHeaders>& headers) - : response_header_(headers) { -} - -std::string RequestThrottlerHeaderAdapter::GetNormalizedValue( - const std::string& key) const { - std::string return_value; - response_header_->GetNormalizedHeader(key, &return_value); - return return_value; -} - -int RequestThrottlerHeaderAdapter::GetResponseCode() const { - return response_header_->response_code(); -} diff --git a/net/request_throttler/request_throttler_header_adapter.h b/net/request_throttler/request_throttler_header_adapter.h deleted file mode 100644 index 86a0d20..0000000 --- a/net/request_throttler/request_throttler_header_adapter.h +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_REQUEST_THROTTLER_REQUEST_THROTTLER_HEADER_ADAPTER_H_ -#define NET_REQUEST_THROTTLER_REQUEST_THROTTLER_HEADER_ADAPTER_H_ - -#include <string> - -#include "base/scoped_ptr.h" -#include "net/http/http_response_headers.h" -#include "net/request_throttler/request_throttler_header_interface.h" - -namespace net { -class HttpResponseHeaders; -} - -// Adapter for the http header interface of the request throttler component. -class RequestThrottlerHeaderAdapter : public RequestThrottlerHeaderInterface { - public: - RequestThrottlerHeaderAdapter( - const scoped_refptr<net::HttpResponseHeaders>& headers); - virtual ~RequestThrottlerHeaderAdapter() {} - - // Implementation of the Http header interface - virtual std::string GetNormalizedValue(const std::string& key) const; - virtual int GetResponseCode() const; - private: - const scoped_refptr<net::HttpResponseHeaders> response_header_; -}; - -#endif // NET_REQUEST_THROTTLER_REQUEST_THROTTLER_HEADER_ADAPTER_H_ diff --git a/net/request_throttler/request_throttler_header_interface.h b/net/request_throttler/request_throttler_header_interface.h deleted file mode 100644 index 021c6e4..0000000 --- a/net/request_throttler/request_throttler_header_interface.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_REQUEST_THROTTLER_REQUEST_THROTTLER_HEADER_INTERFACE_H_ -#define NET_REQUEST_THROTTLER_REQUEST_THROTTLER_HEADER_INTERFACE_H_ - -#include <string> - -// Interface to an HTTP header to enforce we have the methods we need. -class RequestThrottlerHeaderInterface { - public: - virtual ~RequestThrottlerHeaderInterface() {} - - // Method that enables us to fetch the header value by its key. - // ex: location: www.example.com -> key = "location" value = "www.example.com" - // If the key does not exist, it returns an empty string. - virtual std::string GetNormalizedValue(const std::string& key) const = 0; - - // Returns the HTTP response code associated with the request. - virtual int GetResponseCode() const = 0; -}; - -#endif // NET_REQUEST_THROTTLER_REQUEST_THROTTLER_HEADER_INTERFACE_H_ diff --git a/net/request_throttler/request_throttler_manager.cc b/net/request_throttler/request_throttler_manager.cc deleted file mode 100644 index 21ca3fc..0000000 --- a/net/request_throttler/request_throttler_manager.cc +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "net/request_throttler/request_throttler_manager.h" - -#include "base/logging.h" -#include "base/message_loop.h" -#include "base/rand_util.h" -#include "base/string_util.h" - -const unsigned int RequestThrottlerManager::kMaximumNumberOfEntries = 1500; -const unsigned int RequestThrottlerManager::kRequestsBetweenCollecting = 200; - -scoped_refptr<RequestThrottlerEntryInterface> - RequestThrottlerManager::RegisterRequestUrl( - const GURL &url) { - DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_IO); - - // Periodically garbage collect old entries. - requests_since_last_gc_++; - if (requests_since_last_gc_ >= kRequestsBetweenCollecting) { - GarbageCollectEntries(); - requests_since_last_gc_ = 0; - } - - // Normalize the url - std::string url_id = GetIdFromUrl(url); - - // Finds the entry in the map or creates it. - scoped_refptr<RequestThrottlerEntry>& entry = url_entries_[url_id]; - if (entry == NULL) - entry = new RequestThrottlerEntry(); - - return entry; -} - -RequestThrottlerManager::RequestThrottlerManager() - : current_loop_(MessageLoop::current()), - requests_since_last_gc_(0) { -} - -RequestThrottlerManager::~RequestThrottlerManager() { - // Deletes all entries - url_entries_.clear(); -} - -std::string RequestThrottlerManager::GetIdFromUrl(const GURL& url) { - std::string url_id; - url_id += url.scheme(); - url_id += "://"; - url_id += url.host(); - url_id += url.path(); - - return StringToLowerASCII(url_id); -} - -void RequestThrottlerManager::GarbageCollectEntries() { - DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_IO); - UrlEntryMap::iterator i = url_entries_.begin(); - - while (i != url_entries_.end()) { - if ((i->second)->IsEntryOutdated()) { - url_entries_.erase(i++); - } else { - ++i; - } - } - - // In case something broke we want to make sure not to grow indefinitely. - while (url_entries_.size() > kMaximumNumberOfEntries) { - url_entries_.erase(url_entries_.begin()); - } -} - -void RequestThrottlerManager::NotifyRequestBodyWasMalformed(const GURL& url) { - DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_IO); - // Normalize the url - std::string url_id = GetIdFromUrl(url); - UrlEntryMap::iterator i = url_entries_.find(url_id); - - if (i != url_entries_.end()) { - i->second->ReceivedContentWasMalformed(); - } -} diff --git a/net/request_throttler/request_throttler_manager.h b/net/request_throttler/request_throttler_manager.h deleted file mode 100644 index 2ef695f..0000000 --- a/net/request_throttler/request_throttler_manager.h +++ /dev/null @@ -1,79 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef NET_REQUEST_THROTTLER_REQUEST_THROTTLER_MANAGER_H_ -#define NET_REQUEST_THROTTLER_REQUEST_THROTTLER_MANAGER_H_ - -#include <map> -#include <string> - -#include "base/lock.h" -#include "base/non_thread_safe.h" -#include "base/singleton.h" -#include "base/scoped_ptr.h" -#include "base/time.h" -#include "googleurl/src/gurl.h" -#include "net/request_throttler/request_throttler_entry.h" - -class MessageLoop; - -// Class that registers a request throttler entry for each URL being accessed in -// order to supervise traffic. URL Http Request should register their URL in -// this request throttler manager on each request. -class RequestThrottlerManager { - public: - // Must be called for every request, returns the request throttler entry - // associated with the URL. The caller must inform this entry of some events. - // Please refer to request_throttler_entry.h for further informations. - scoped_refptr<RequestThrottlerEntryInterface> RegisterRequestUrl( - const GURL& url); - - // This method is used by higher level modules which can notify this class if - // the response they received was malformed. It is useful because - // in the case where the response header returned 200 response code but had - // a malformed content body we will categorize it as a success and so we - // defer this decision to the module that had requested the resource. - void NotifyRequestBodyWasMalformed(const GURL& url); - - protected: - RequestThrottlerManager(); - virtual ~RequestThrottlerManager(); - - // From each URL we generate an ID composed of the host and path - // that allows us to uniquely map an entry to it. - typedef std::map<std::string, scoped_refptr<RequestThrottlerEntry> > - UrlEntryMap; - - friend struct DefaultSingletonTraits<RequestThrottlerManager>; - - // Map that contains a list of URL ID and their matching - // RequestThrottlerEntry. - UrlEntryMap url_entries_; - - // Method that allows us to transform an URL into an ID that is useful and - // can be used in our map. Resulting IDs will be lowercase and be missing both - // the query string and fragment. - std::string GetIdFromUrl(const GURL& url); - - // Method that ensures the map gets cleaned from time to time. The period at - // which this GarbageCollection happens is adjustable with the - // kRequestBetweenCollecting constant. - void GarbageCollectEntries(); - - private: - MessageLoop* current_loop_; - - // Maximum number of entries that we are willing to collect in our map. - static const unsigned int kMaximumNumberOfEntries; - // Number of requests that will be made between garbage collection. - static const unsigned int kRequestsBetweenCollecting; - - // This keeps track of how many request have been made. Used with - // GarbageCollectEntries. - unsigned int requests_since_last_gc_; - - DISALLOW_COPY_AND_ASSIGN(RequestThrottlerManager); -}; - -#endif // NET_REQUEST_THROTTLER_REQUEST_THROTTLER_MANAGER_H_ diff --git a/net/request_throttler/request_throttler_unittest.cc b/net/request_throttler/request_throttler_unittest.cc deleted file mode 100644 index d43b555..0000000 --- a/net/request_throttler/request_throttler_unittest.cc +++ /dev/null @@ -1,302 +0,0 @@ -// Copyright (c) 2010 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include "base/pickle.h" -#include "base/scoped_ptr.h" -#include "base/string_number_conversions.h" -#include "base/string_util.h" -#include "base/time.h" -#include "net/base/test_completion_callback.h" -#include "net/request_throttler/request_throttler_manager.h" -#include "net/request_throttler/request_throttler_header_interface.h" -#include "net/url_request/url_request_context.h" -#include "testing/gtest/include/gtest/gtest.h" - -using base::TimeDelta; -using base::TimeTicks; - -namespace { -class MockRequestThrottlerManager; - -class MockRequestThrottlerEntry : public RequestThrottlerEntry { - public : - MockRequestThrottlerEntry() {} - MockRequestThrottlerEntry(TimeTicks release_time, TimeTicks fake_now) - : fake_time_now_(fake_now) { - release_time_ = release_time; - } - virtual ~MockRequestThrottlerEntry() {} - - void ResetToBlank(TimeTicks time_now) { - fake_time_now_ = time_now; - release_time_ = time_now; - num_times_delayed_ = 0; - } - - // Overloaded for test - virtual TimeTicks GetTimeNow() const { return fake_time_now_; } - - TimeTicks release_time() const { return release_time_; } - void set_release_time(TimeTicks time) { release_time_ = time; } - - TimeTicks fake_time_now_; -}; - -class MockRequestThrottlerHeaderAdapter - : public RequestThrottlerHeaderInterface { - public: - MockRequestThrottlerHeaderAdapter() - : fake_retry_value_("0.0"), - fake_response_code_(0) { - } - - MockRequestThrottlerHeaderAdapter(const std::string& retry_value, - const int response_code) - : fake_retry_value_(retry_value), - fake_response_code_(response_code) { - } - - ~MockRequestThrottlerHeaderAdapter() {} - - virtual std::string GetNormalizedValue(const std::string& key) const { - if (key == MockRequestThrottlerEntry::kRetryHeaderName) - return fake_retry_value_; - return ""; - } - - virtual int GetResponseCode() const { return fake_response_code_; } - - std::string fake_retry_value_; - int fake_response_code_; -}; - -class MockRequestThrottlerManager : public RequestThrottlerManager { - public: - MockRequestThrottlerManager() {} - virtual ~MockRequestThrottlerManager() {} - - // Method to process the url using RequestThrottlerManager protected method. - std::string DoGetUrlIdFromUrl(const GURL& url) { return GetIdFromUrl(url); } - - // Method to use the garbage collecting method of RequestThrottlerManager. - void DoGarbageCollectEntries() { GarbageCollectEntries(); } - - // Returns the number of entries in the host map. - int GetNumberOfEntries() { return url_entries_.size(); } - - void CreateEntry(const bool is_outdated); - - static int create_entry_index; -}; - -/*------------------ Mock request throttler manager --------------------------*/ -int MockRequestThrottlerManager::create_entry_index = 0; - -void MockRequestThrottlerManager::CreateEntry(const bool is_outdated) { - TimeTicks time = TimeTicks::Now(); - if (is_outdated) { - time -= TimeDelta::FromSeconds( - MockRequestThrottlerEntry::kEntryLifetimeSec); - time -= TimeDelta::FromSeconds(1); - } - std::string index = base::IntToString(create_entry_index++); - url_entries_[index] = new MockRequestThrottlerEntry(time, TimeTicks::Now()); -} - -/* ---------------- Request throttler entry test -----------------------------*/ -struct TimeAndBool { - TimeAndBool(TimeTicks time_value, bool expected, int line_num) { - time = time_value; - result = expected; - line = line_num; - } - TimeTicks time; - bool result; - int line; -}; - -struct GurlAndString { - GurlAndString(GURL url_value, const std::string& expected, int line_num) { - url = url_value; - result = expected; - line = line_num; - } - GURL url; - std::string result; - int line; -}; - -class RequestThrottlerEntryTest : public ::testing::Test { - protected: - virtual void SetUp(); - TimeTicks now_; - TimeDelta delay_; - scoped_refptr<MockRequestThrottlerEntry> entry_; -}; - -void RequestThrottlerEntryTest::SetUp() { - now_ = TimeTicks::Now(); - entry_ = new MockRequestThrottlerEntry(); - entry_->ResetToBlank(now_); -} - -std::ostream& operator<<(std::ostream& out, const base::TimeTicks& time) { - return out << time.ToInternalValue(); -} - -TEST_F(RequestThrottlerEntryTest, InterfaceRequestNotAllowed) { - entry_->set_release_time(entry_->fake_time_now_ + - TimeDelta::FromMilliseconds(1)); - EXPECT_FALSE(entry_->IsRequestAllowed()); -} - -TEST_F(RequestThrottlerEntryTest, InterfaceRequestAllowed) { - entry_->set_release_time(entry_->fake_time_now_); - EXPECT_TRUE(entry_->IsRequestAllowed()); - entry_->set_release_time(entry_->fake_time_now_ - - TimeDelta::FromMilliseconds(1)); - EXPECT_TRUE(entry_->IsRequestAllowed()); -} - -TEST_F(RequestThrottlerEntryTest, InterfaceUpdateRetryAfter) { - // If the response we received as a retry-after field, - // the request should be delayed. - MockRequestThrottlerHeaderAdapter header_w_delay_header("5.5", 200); - entry_->UpdateWithResponse(&header_w_delay_header); - EXPECT_GT(entry_->release_time(), entry_->fake_time_now_) << - "When the server put a positive value in retry-after we should " - "increase release_time"; - - entry_->ResetToBlank(now_); - header_w_delay_header.fake_retry_value_ = "-5.5"; - EXPECT_EQ(entry_->release_time(), entry_->fake_time_now_) << - "When given a negative value, it should not change the release_time"; -} - -TEST_F(RequestThrottlerEntryTest, InterfaceUpdateFailure) { - MockRequestThrottlerHeaderAdapter failure_response("0", 505); - entry_->UpdateWithResponse(&failure_response); - EXPECT_GT(entry_->release_time(), entry_->fake_time_now_) << - "A failure should increase the release_time"; -} - -TEST_F(RequestThrottlerEntryTest, InterfaceUpdateSuccess) { - MockRequestThrottlerHeaderAdapter success_response("0", 200); - entry_->UpdateWithResponse(&success_response); - EXPECT_EQ(entry_->release_time(), entry_->fake_time_now_) << - "A success should not add any delay"; -} - -TEST_F(RequestThrottlerEntryTest, InterfaceUpdateSuccessThenFailure) { - MockRequestThrottlerHeaderAdapter failure_response("0", 500), - success_response("0", 200); - entry_->UpdateWithResponse(&success_response); - entry_->UpdateWithResponse(&failure_response); - EXPECT_GT(entry_->release_time(), entry_->fake_time_now_) << - "This scenario should add delay"; -} - -TEST_F(RequestThrottlerEntryTest, IsEntryReallyOutdated) { - TimeDelta lifetime = TimeDelta::FromSeconds( - MockRequestThrottlerEntry::kEntryLifetimeSec); - const TimeDelta kFiveMs = TimeDelta::FromMilliseconds(5); - - TimeAndBool test_values[] = { - TimeAndBool(now_, false, __LINE__), - TimeAndBool(now_ - kFiveMs, false, __LINE__), - TimeAndBool(now_ + kFiveMs, false, __LINE__), - TimeAndBool(now_ - lifetime, false, __LINE__), - TimeAndBool(now_ - (lifetime + kFiveMs), true, __LINE__)}; - - for (unsigned int i = 0; i < arraysize(test_values); ++i) { - entry_->set_release_time(test_values[i].time); - EXPECT_EQ(entry_->IsEntryOutdated(), test_values[i].result) << - "Test case #" << i << " line " << test_values[i].line << " failed"; - } -} - -TEST_F(RequestThrottlerEntryTest, MaxAllowedBackoff) { - for (int i = 0; i < 30; ++i) { - MockRequestThrottlerHeaderAdapter response_adapter("0.0", 505); - entry_->UpdateWithResponse(&response_adapter); - } - - delay_ = entry_->release_time() - now_; - EXPECT_EQ(delay_.InMilliseconds(), - MockRequestThrottlerEntry::kMaximumBackoffMs); -} - -TEST_F(RequestThrottlerEntryTest, MalformedContent) { - for (int i = 0; i < 5; ++i) { - MockRequestThrottlerHeaderAdapter response_adapter("0.0", 505); - entry_->UpdateWithResponse(&response_adapter); - } - TimeTicks release_after_failures = entry_->release_time(); - - // Send a success code to reset backoff. - MockRequestThrottlerHeaderAdapter response_adapter("0.0", 200); - entry_->UpdateWithResponse(&response_adapter); - EXPECT_EQ(entry_->release_time(), release_after_failures); - - // Then inform the entry that previous package was malformed - // it is suppose to regenerate previous state. - entry_->ReceivedContentWasMalformed(); - EXPECT_GT(entry_->release_time(), release_after_failures); -} - -TEST(RequestThrottlerManager, IsUrlStandardised) { - MockRequestThrottlerManager manager; - GurlAndString test_values[] = { - GurlAndString(GURL("http://www.example.com"), - std::string("http://www.example.com/"), __LINE__), - GurlAndString(GURL("http://www.Example.com"), - std::string("http://www.example.com/"), __LINE__), - GurlAndString(GURL("http://www.ex4mple.com/Pr4c71c41"), - std::string("http://www.ex4mple.com/pr4c71c41"), __LINE__), - GurlAndString(GURL("http://www.example.com/0/token/false"), - std::string("http://www.example.com/0/token/false"), - __LINE__), - GurlAndString(GURL("http://www.example.com/index.php?code=javascript"), - std::string("http://www.example.com/index.php"), __LINE__), - GurlAndString(GURL("http://www.example.com/index.php?code=1#superEntry"), - std::string("http://www.example.com/index.php"), - __LINE__)}; - - for (unsigned int i = 0; i < arraysize(test_values); ++i) { - std::string temp = manager.DoGetUrlIdFromUrl(test_values[i].url); - EXPECT_EQ(temp, test_values[i].result) << - "Test case #" << i << " line " << test_values[i].line << " failed"; - } -} - -TEST(RequestThrottlerManager, AreEntriesBeingCollected ) { - MockRequestThrottlerManager manager; - - manager.CreateEntry(true); // true = Entry is outdated. - manager.CreateEntry(true); - manager.CreateEntry(true); - manager.DoGarbageCollectEntries(); - EXPECT_EQ(0, manager.GetNumberOfEntries()); - - manager.CreateEntry(false); - manager.CreateEntry(false); - manager.CreateEntry(false); - manager.CreateEntry(true); - manager.DoGarbageCollectEntries(); - EXPECT_EQ(3, manager.GetNumberOfEntries()); -} - -TEST(RequestThrottlerManager, IsHostBeingRegistered) { - MockRequestThrottlerManager manager; - - manager.RegisterRequestUrl(GURL("http://www.example.com/")); - manager.RegisterRequestUrl(GURL("http://www.google.com/")); - manager.RegisterRequestUrl(GURL("http://www.google.com/index/0")); - manager.RegisterRequestUrl(GURL("http://www.google.com/index/0?code=1")); - manager.RegisterRequestUrl(GURL("http://www.google.com/index/0#lolsaure")); - - EXPECT_EQ(3, manager.GetNumberOfEntries()); -} - -} // namespace diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc index 5564628..cbccff2 100644 --- a/net/url_request/url_request_http_job.cc +++ b/net/url_request/url_request_http_job.cc @@ -27,7 +27,6 @@ #include "net/http/http_transaction.h" #include "net/http/http_transaction_factory.h" #include "net/http/http_util.h" -#include "net/request_throttler/request_throttler_header_adapter.h" #include "net/url_request/https_prober.h" #include "net/url_request/url_request.h" #include "net/url_request/url_request_context.h" @@ -92,8 +91,6 @@ URLRequestHttpJob::URLRequestHttpJob(URLRequest* request) this, &URLRequestHttpJob::OnReadCompleted)), read_in_progress_(false), transaction_(NULL), - throttling_entry_(Singleton<RequestThrottlerManager>::get()-> - RegisterRequestUrl(request->url())), sdch_dictionary_advertised_(false), sdch_test_activated_(false), sdch_test_control_(false), @@ -572,11 +569,6 @@ void URLRequestHttpJob::NotifyHeadersComplete() { // also need this info. is_cached_content_ = response_info_->was_cached; - if (!is_cached_content_) { - RequestThrottlerHeaderAdapter response_adapter(response_info_->headers); - throttling_entry_->UpdateWithResponse(&response_adapter); - } - ProcessStrictTransportSecurityHeader(); if (SdchManager::Global() && @@ -624,37 +616,30 @@ void URLRequestHttpJob::StartTransaction() { // If we already have a transaction, then we should restart the transaction // with auth provided by username_ and password_. - int return_value; - + int rv; if (transaction_.get()) { - return_value = transaction_->RestartWithAuth(username_, - password_, &start_callback_); + rv = transaction_->RestartWithAuth(username_, password_, &start_callback_); username_.clear(); password_.clear(); } else { DCHECK(request_->context()); DCHECK(request_->context()->http_transaction_factory()); - return_value = request_->context()->http_transaction_factory()-> - CreateTransaction(&transaction_); - if (return_value == net::OK) { - if (throttling_entry_->IsRequestAllowed()) { - return_value = transaction_->Start( - &request_info_, &start_callback_, request_->net_log()); - } else { - // Special error code for the exponential back-off module. - return_value = net::ERR_TEMPORARILY_THROTTLED_BY_DDOS; - } + rv = request_->context()->http_transaction_factory()->CreateTransaction( + &transaction_); + if (rv == net::OK) { + rv = transaction_->Start( + &request_info_, &start_callback_, request_->net_log()); } } - if (return_value == net::ERR_IO_PENDING) + if (rv == net::ERR_IO_PENDING) return; // The transaction started synchronously, but we need to notify the // URLRequest delegate via the message loop. MessageLoop::current()->PostTask(FROM_HERE, NewRunnableMethod( - this, &URLRequestHttpJob::OnStartCompleted, return_value)); + this, &URLRequestHttpJob::OnStartCompleted, rv)); } void URLRequestHttpJob::AddExtraHeaders() { diff --git a/net/url_request/url_request_http_job.h b/net/url_request/url_request_http_job.h index 79511f2..ea2e544 100644 --- a/net/url_request/url_request_http_job.h +++ b/net/url_request/url_request_http_job.h @@ -11,12 +11,10 @@ #include <vector> #include "base/scoped_ptr.h" -#include "base/string_util.h" #include "base/string16.h" #include "net/base/auth.h" #include "net/base/completion_callback.h" #include "net/http/http_request_info.h" -#include "net/request_throttler/request_throttler_manager.h" #include "net/url_request/url_request_job.h" namespace net { @@ -115,9 +113,6 @@ class URLRequestHttpJob : public URLRequestJob { scoped_ptr<net::HttpTransaction> transaction_; - // This is used to supervise traffic and enforce exponential back-off. - scoped_refptr<RequestThrottlerEntryInterface> throttling_entry_; - // Indicated if an SDCH dictionary was advertised, and hence an SDCH // compressed response is expected. We use this to help detect (accidental?) // proxy corruption of a response, which sometimes marks SDCH content as |