diff options
-rw-r--r-- | content/browser/renderer_host/resource_dispatcher_host.cc | 21 | ||||
-rw-r--r-- | content/browser/renderer_host/resource_dispatcher_host.h | 9 | ||||
-rw-r--r-- | content/browser/tab_contents/tab_contents.cc | 2 | ||||
-rw-r--r-- | net/base/load_flags_list.h | 4 | ||||
-rw-r--r-- | net/url_request/url_request_http_job.cc | 2 | ||||
-rw-r--r-- | net/url_request/url_request_throttler_entry.cc | 11 | ||||
-rw-r--r-- | net/url_request/url_request_throttler_entry.h | 7 | ||||
-rw-r--r-- | net/url_request/url_request_throttler_entry_interface.h | 7 | ||||
-rw-r--r-- | net/url_request/url_request_throttler_simulation_unittest.cc | 2 | ||||
-rw-r--r-- | net/url_request/url_request_throttler_unittest.cc | 32 |
10 files changed, 80 insertions, 17 deletions
diff --git a/content/browser/renderer_host/resource_dispatcher_host.cc b/content/browser/renderer_host/resource_dispatcher_host.cc index 24ef682..8e9f132 100644 --- a/content/browser/renderer_host/resource_dispatcher_host.cc +++ b/content/browser/renderer_host/resource_dispatcher_host.cc @@ -18,7 +18,6 @@ #include "base/metrics/histogram.h" #include "base/shared_memory.h" #include "base/stl_util.h" -#include "base/time.h" #include "chrome/browser/download/download_file_manager.h" #include "chrome/browser/download/download_manager.h" #include "chrome/browser/download/download_request_limiter.h" @@ -116,6 +115,14 @@ const int kMaxPendingDataMessages = 20; // This bound is 25MB, which allows for around 6000 outstanding requests. const int kMaxOutstandingRequestsCostPerProcess = 26214400; +// The number of milliseconds after noting a user gesture that we will +// tag newly-created URLRequest objects with the +// net::LOAD_MAYBE_USER_GESTURE load flag. This is a fairly arbitrary +// guess at how long to expect direct impact from a user gesture, but +// this should be OK as the load flag is a best-effort thing only, +// rather than being intended as fully accurate. +const int kUserGestureWindowMs = 3500; + // All possible error codes from the network module. Note that the error codes // are all positive (since histograms expect positive sample values). const int kAllNetErrorCodes[] = { @@ -1409,6 +1416,12 @@ void ResourceDispatcherHost::BeginRequestInternal(net::URLRequest* request) { DCHECK(!request->is_pending()); ResourceDispatcherHostRequestInfo* info = InfoForRequest(request); + if ((TimeTicks::Now() - last_user_gesture_time_) < + TimeDelta::FromMilliseconds(kUserGestureWindowMs)) { + request->set_load_flags( + request->load_flags() | net::LOAD_MAYBE_USER_GESTURE); + } + // Add the memory estimate that starting this request will consume. info->set_memory_cost(CalculateApproximateMemoryCost(request)); int memory_cost = IncrementOutstandingRequestsMemoryCost(info->memory_cost(), @@ -1674,6 +1687,12 @@ void ResourceDispatcherHost::OnResponseCompleted(net::URLRequest* request) { // call until later. We will notify the world and clean up when we resume. } +void ResourceDispatcherHost::OnUserGesture(TabContents* tab) { + download_request_limiter()->OnUserGesture(tab); + + last_user_gesture_time_ = TimeTicks::Now(); +} + // static ResourceDispatcherHostRequestInfo* ResourceDispatcherHost::InfoForRequest( net::URLRequest* request) { diff --git a/content/browser/renderer_host/resource_dispatcher_host.h b/content/browser/renderer_host/resource_dispatcher_host.h index d6c5ce7..27a52ac 100644 --- a/content/browser/renderer_host/resource_dispatcher_host.h +++ b/content/browser/renderer_host/resource_dispatcher_host.h @@ -20,6 +20,7 @@ #include "base/basictypes.h" #include "base/gtest_prod_util.h" #include "base/memory/scoped_ptr.h" +#include "base/time.h" #include "base/timer.h" #include "content/browser/renderer_host/resource_queue.h" #include "content/common/child_process_info.h" @@ -40,6 +41,7 @@ class ResourceHandler; class ResourceMessageFilter; class SaveFileManager; class SSLClientAuthHandler; +class TabContents; class WebKitThread; struct DownloadSaveInfo; struct GlobalRequestID; @@ -201,6 +203,8 @@ class ResourceDispatcherHost : public net::URLRequest::Delegate { void OnResponseCompleted(net::URLRequest* request); + void OnUserGesture(TabContents* tab); + // Helper functions to get the dispatcher's request info for the request. // If the dispatcher didn't create the request then NULL is returned. static ResourceDispatcherHostRequestInfo* InfoForRequest( @@ -502,6 +506,11 @@ class ResourceDispatcherHost : public net::URLRequest::Delegate { // kAvgBytesPerOutstandingRequest) int max_outstanding_requests_cost_per_process_; + // Time of the last user gesture. Stored so that we can add a load + // flag to requests occurring soon after a gesture to indicate they + // may be because of explicit user action. + base::TimeTicks last_user_gesture_time_; + // Used during IPC message dispatching so that the handlers can get a pointer // to the source of the message. ResourceMessageFilter* filter_; diff --git a/content/browser/tab_contents/tab_contents.cc b/content/browser/tab_contents/tab_contents.cc index 8ff4d06..d256175 100644 --- a/content/browser/tab_contents/tab_contents.cc +++ b/content/browser/tab_contents/tab_contents.cc @@ -1742,7 +1742,7 @@ void TabContents::OnUserGesture() { ResourceDispatcherHost* rdh = content::GetContentClient()->browser()->GetResourceDispatcherHost(); if (rdh) // NULL in unittests. - rdh->download_request_limiter()->OnUserGesture(this); + rdh->OnUserGesture(this); } void TabContents::OnIgnoredUIEvent() { diff --git a/net/base/load_flags_list.h b/net/base/load_flags_list.h index 242a3de..aeaca85 100644 --- a/net/base/load_flags_list.h +++ b/net/base/load_flags_list.h @@ -114,3 +114,7 @@ LOAD_FLAG(IGNORE_LIMITS, 1 << 25) // default credentials may still be used for authentication. LOAD_FLAG(DO_NOT_PROMPT_FOR_LOGIN, 1 << 26) +// Indicates that the operation is somewhat likely to be due to an +// explicit user action. This can be used as a hint to treat the +// request with higher priority. +LOAD_FLAG(MAYBE_USER_GESTURE, 1 << 27) diff --git a/net/url_request/url_request_http_job.cc b/net/url_request/url_request_http_job.cc index a98ca5d..a5c1edf 100644 --- a/net/url_request/url_request_http_job.cc +++ b/net/url_request/url_request_http_job.cc @@ -397,7 +397,7 @@ void URLRequestHttpJob::StartTransactionInternal() { &transaction_); if (rv == OK) { if (!URLRequestThrottlerManager::GetInstance()->enforce_throttling() || - !throttling_entry_->IsDuringExponentialBackoff()) { + !throttling_entry_->ShouldRejectRequest(request_info_.load_flags)) { rv = transaction_->Start( &request_info_, &start_callback_, request_->net_log()); start_time_ = base::TimeTicks::Now(); diff --git a/net/url_request/url_request_throttler_entry.cc b/net/url_request/url_request_throttler_entry.cc index bf831ca..a56e414 100644 --- a/net/url_request/url_request_throttler_entry.cc +++ b/net/url_request/url_request_throttler_entry.cc @@ -12,6 +12,7 @@ #include "base/rand_util.h" #include "base/string_number_conversions.h" #include "base/values.h" +#include "net/base/load_flags.h" #include "net/base/net_log.h" #include "net/url_request/url_request_throttler_header_interface.h" #include "net/url_request/url_request_throttler_manager.h" @@ -178,9 +179,10 @@ void URLRequestThrottlerEntry::DetachManager() { manager_ = NULL; } -bool URLRequestThrottlerEntry::IsDuringExponentialBackoff() const { +bool URLRequestThrottlerEntry::ShouldRejectRequest(int load_flags) const { bool reject_request = false; - if (!is_backoff_disabled_ && GetBackoffEntry()->ShouldRejectRequest()) { + if (!is_backoff_disabled_ && !ExplicitUserRequest(load_flags) && + GetBackoffEntry()->ShouldRejectRequest()) { int num_failures = GetBackoffEntry()->failure_count(); int release_after_ms = (GetBackoffEntry()->GetReleaseTime() - base::TimeTicks::Now()) @@ -444,4 +446,9 @@ BackoffEntry* URLRequestThrottlerEntry::GetBackoffEntry() { return &backoff_entry_; } +// static +bool URLRequestThrottlerEntry::ExplicitUserRequest(const int load_flags) { + return (load_flags & LOAD_MAYBE_USER_GESTURE) != 0; +} + } // namespace net diff --git a/net/url_request/url_request_throttler_entry.h b/net/url_request/url_request_throttler_entry.h index 10f1adc..df03fb3 100644 --- a/net/url_request/url_request_throttler_entry.h +++ b/net/url_request/url_request_throttler_entry.h @@ -97,7 +97,7 @@ class NET_API URLRequestThrottlerEntry void DetachManager(); // Implementation of URLRequestThrottlerEntryInterface. - virtual bool IsDuringExponentialBackoff() const; + virtual bool ShouldRejectRequest(int load_flags) const; virtual int64 ReserveSendingTimeForNextRequest( const base::TimeTicks& earliest_time); virtual base::TimeTicks GetExponentialBackoffReleaseTime() const; @@ -134,6 +134,11 @@ class NET_API URLRequestThrottlerEntry virtual const BackoffEntry* GetBackoffEntry() const; virtual BackoffEntry* GetBackoffEntry(); + // Returns true if |load_flags| contains a flag that indicates an + // explicit request by the user to load the resource. We never + // throttle requests with such load flags. + static bool ExplicitUserRequest(const int load_flags); + // Used by tests. base::TimeTicks sliding_window_release_time() const { return sliding_window_release_time_; diff --git a/net/url_request/url_request_throttler_entry_interface.h b/net/url_request/url_request_throttler_entry_interface.h index 86feb9f..b09ddcc 100644 --- a/net/url_request/url_request_throttler_entry_interface.h +++ b/net/url_request/url_request_throttler_entry_interface.h @@ -24,10 +24,13 @@ class NET_API URLRequestThrottlerEntryInterface URLRequestThrottlerEntryInterface() {} // Returns true when we have encountered server errors and are doing - // exponential back-off. + // exponential back-off, unless the request has |load_flags| (from + // net/base/load_flags.h) that mean it is likely to be + // user-initiated. + // // URLRequestHttpJob checks this method prior to every request; it // cancels requests if this method returns true. - virtual bool IsDuringExponentialBackoff() const = 0; + virtual bool ShouldRejectRequest(int load_flags) const = 0; // Calculates a recommended sending time for the next request and reserves it. // The sending time is not earlier than the current exponential back-off diff --git a/net/url_request/url_request_throttler_simulation_unittest.cc b/net/url_request/url_request_throttler_simulation_unittest.cc index 287b0a7..5ee1746 100644 --- a/net/url_request/url_request_throttler_simulation_unittest.cc +++ b/net/url_request/url_request_throttler_simulation_unittest.cc @@ -425,7 +425,7 @@ class Requester : public DiscreteTimeSimulation::Actor { if (throttler_entry_->fake_now() - time_of_last_attempt_ > effective_delay) { - if (!throttler_entry_->IsDuringExponentialBackoff()) { + if (!throttler_entry_->ShouldRejectRequest(0)) { int status_code = server_->HandleRequest(); MockURLRequestThrottlerHeaderAdapter response_headers(status_code); throttler_entry_->UpdateWithResponse("", &response_headers); diff --git a/net/url_request/url_request_throttler_unittest.cc b/net/url_request/url_request_throttler_unittest.cc index 8e9734f..4c8f492 100644 --- a/net/url_request/url_request_throttler_unittest.cc +++ b/net/url_request/url_request_throttler_unittest.cc @@ -10,6 +10,7 @@ #include "base/stringprintf.h" #include "base/string_number_conversions.h" #include "base/time.h" +#include "net/base/load_flags.h" #include "net/base/test_completion_callback.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_throttler_header_interface.h" @@ -67,6 +68,10 @@ class MockURLRequestThrottlerEntry : public URLRequestThrottlerEntry { return &mock_backoff_entry_; } + static bool ExplicitUserRequest(int load_flags) { + return URLRequestThrottlerEntry::ExplicitUserRequest(load_flags); + } + void ResetToBlank(const TimeTicks& time_now) { fake_time_now_ = time_now; mock_backoff_entry_.set_fake_now(time_now); @@ -229,19 +234,22 @@ std::ostream& operator<<(std::ostream& out, const base::TimeTicks& time) { TEST_F(URLRequestThrottlerEntryTest, InterfaceDuringExponentialBackoff) { entry_->set_exponential_backoff_release_time( entry_->fake_time_now_ + TimeDelta::FromMilliseconds(1)); - EXPECT_TRUE(entry_->IsDuringExponentialBackoff()); + EXPECT_TRUE(entry_->ShouldRejectRequest(0)); + + // Also end-to-end test the load flags exceptions. + EXPECT_FALSE(entry_->ShouldRejectRequest(LOAD_MAYBE_USER_GESTURE)); CalculateHistogramDeltas(); - ASSERT_EQ(0, samples_["Throttling.RequestThrottled"].counts(0)); + ASSERT_EQ(1, samples_["Throttling.RequestThrottled"].counts(0)); ASSERT_EQ(1, samples_["Throttling.RequestThrottled"].counts(1)); } TEST_F(URLRequestThrottlerEntryTest, InterfaceNotDuringExponentialBackoff) { entry_->set_exponential_backoff_release_time(entry_->fake_time_now_); - EXPECT_FALSE(entry_->IsDuringExponentialBackoff()); + EXPECT_FALSE(entry_->ShouldRejectRequest(0)); entry_->set_exponential_backoff_release_time( entry_->fake_time_now_ - TimeDelta::FromMilliseconds(1)); - EXPECT_FALSE(entry_->IsDuringExponentialBackoff()); + EXPECT_FALSE(entry_->ShouldRejectRequest(0)); CalculateHistogramDeltas(); ASSERT_EQ(2, samples_["Throttling.RequestThrottled"].counts(0)); @@ -377,6 +385,14 @@ TEST_F(URLRequestThrottlerEntryTest, SlidingWindow) { EXPECT_EQ(time_4, entry_->sliding_window_release_time()); } +TEST_F(URLRequestThrottlerEntryTest, ExplicitUserRequest) { + ASSERT_FALSE(MockURLRequestThrottlerEntry::ExplicitUserRequest(0)); + ASSERT_TRUE(MockURLRequestThrottlerEntry::ExplicitUserRequest( + LOAD_MAYBE_USER_GESTURE)); + ASSERT_FALSE(MockURLRequestThrottlerEntry::ExplicitUserRequest( + ~LOAD_MAYBE_USER_GESTURE)); +} + TEST(URLRequestThrottlerManager, IsUrlStandardised) { MockURLRequestThrottlerManager manager; GurlAndString test_values[] = { @@ -444,13 +460,13 @@ TEST(URLRequestThrottlerManager, IsHostBeingRegistered) { void ExpectEntryAllowsAllOnErrorIfOptedOut( net::URLRequestThrottlerEntryInterface* entry, bool opted_out) { - EXPECT_FALSE(entry->IsDuringExponentialBackoff()); + EXPECT_FALSE(entry->ShouldRejectRequest(0)); MockURLRequestThrottlerHeaderAdapter failure_adapter(503); for (int i = 0; i < 10; ++i) { // Host doesn't really matter in this scenario so we skip it. entry->UpdateWithResponse("", &failure_adapter); } - EXPECT_NE(opted_out, entry->IsDuringExponentialBackoff()); + EXPECT_NE(opted_out, entry->ShouldRejectRequest(0)); if (opted_out) { // We're not mocking out GetTimeNow() in this scenario @@ -510,7 +526,7 @@ TEST(URLRequestThrottlerManager, ClearOnNetworkChange) { // Host doesn't really matter in this scenario so we skip it. entry_before->UpdateWithResponse("", &failure_adapter); } - EXPECT_TRUE(entry_before->IsDuringExponentialBackoff()); + EXPECT_TRUE(entry_before->ShouldRejectRequest(0)); switch (i) { case 0: @@ -528,7 +544,7 @@ TEST(URLRequestThrottlerManager, ClearOnNetworkChange) { scoped_refptr<net::URLRequestThrottlerEntryInterface> entry_after = manager.RegisterRequestUrl(GURL("http://www.example.com/")); - EXPECT_FALSE(entry_after->IsDuringExponentialBackoff()); + EXPECT_FALSE(entry_after->ShouldRejectRequest(0)); } } |