summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--content/browser/renderer_host/resource_dispatcher_host.cc21
-rw-r--r--content/browser/renderer_host/resource_dispatcher_host.h9
-rw-r--r--content/browser/tab_contents/tab_contents.cc2
-rw-r--r--net/base/load_flags_list.h4
-rw-r--r--net/url_request/url_request_http_job.cc2
-rw-r--r--net/url_request/url_request_throttler_entry.cc11
-rw-r--r--net/url_request/url_request_throttler_entry.h7
-rw-r--r--net/url_request/url_request_throttler_entry_interface.h7
-rw-r--r--net/url_request/url_request_throttler_simulation_unittest.cc2
-rw-r--r--net/url_request/url_request_throttler_unittest.cc32
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));
}
}