summaryrefslogtreecommitdiffstats
path: root/chrome/browser/extensions
diff options
context:
space:
mode:
authorkalman@chromium.org <kalman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-31 09:45:29 +0000
committerkalman@chromium.org <kalman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-08-31 09:45:29 +0000
commit85231d73b03552f369a32ce640189c531e42cf96 (patch)
treede53e725fa0711ea866b0a1a9d0678c0b51c1738 /chrome/browser/extensions
parenta045f4e35e577c164c1f5c2d9cbbfd0cbd23153c (diff)
downloadchromium_src-85231d73b03552f369a32ce640189c531e42cf96.zip
chromium_src-85231d73b03552f369a32ce640189c531e42cf96.tar.gz
chromium_src-85231d73b03552f369a32ce640189c531e42cf96.tar.bz2
Make all quota-exceeding messages in the storage API explain what the failure
is. This involves adding descriptions to all errors from ExtensionsQuotaService, affecting the other APIs that use this (bookmarks and webRequest). BUG=144533 Review URL: https://chromiumcodereview.appspot.com/10871034 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@154415 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/extensions')
-rw-r--r--chrome/browser/extensions/api/test/test_api.cc2
-rw-r--r--chrome/browser/extensions/api/web_request/web_request_api.cc15
-rw-r--r--chrome/browser/extensions/api/web_request/web_request_api.h2
-rw-r--r--chrome/browser/extensions/extension_function.cc4
-rw-r--r--chrome/browser/extensions/extension_function.h2
-rw-r--r--chrome/browser/extensions/extension_function_dispatcher.cc18
-rw-r--r--chrome/browser/extensions/extensions_quota_service.cc66
-rw-r--r--chrome/browser/extensions/extensions_quota_service.h50
-rw-r--r--chrome/browser/extensions/extensions_quota_service_unittest.cc146
-rw-r--r--chrome/browser/extensions/settings/settings_api.cc7
-rw-r--r--chrome/browser/extensions/settings/settings_storage_quota_enforcer.cc10
11 files changed, 193 insertions, 129 deletions
diff --git a/chrome/browser/extensions/api/test/test_api.cc b/chrome/browser/extensions/api/test/test_api.cc
index 8c4c27b..0468115 100644
--- a/chrome/browser/extensions/api/test/test_api.cc
+++ b/chrome/browser/extensions/api/test/test_api.cc
@@ -80,7 +80,7 @@ bool TestResetQuotaFunction::RunImpl() {
ExtensionService* service = profile()->GetExtensionService();
ExtensionsQuotaService* quota = service->quota_service();
quota->Purge();
- quota->violators_.clear();
+ quota->violation_errors_.clear();
return true;
}
diff --git a/chrome/browser/extensions/api/web_request/web_request_api.cc b/chrome/browser/extensions/api/web_request/web_request_api.cc
index 665c484..74d9a1a 100644
--- a/chrome/browser/extensions/api/web_request/web_request_api.cc
+++ b/chrome/browser/extensions/api/web_request/web_request_api.cc
@@ -31,6 +31,7 @@
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/renderer_host/chrome_render_message_filter.h"
#include "chrome/browser/renderer_host/web_cache_manager.h"
+#include "chrome/common/extensions/api/web_request.h"
#include "chrome/common/extensions/event_filtering_info.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_constants.h"
@@ -59,6 +60,7 @@ using extensions::web_navigation_api_helpers::GetFrameId;
namespace helpers = extension_web_request_api_helpers;
namespace keys = extension_web_request_api_constants;
+namespace web_request = extensions::api::web_request;
namespace {
@@ -1557,7 +1559,10 @@ void ExtensionWebRequestEventRouter::ClearSignaled(uint64 request_id,
class ClearCacheQuotaHeuristic : public QuotaLimitHeuristic {
public:
ClearCacheQuotaHeuristic(const Config& config, BucketMapper* map)
- : QuotaLimitHeuristic(config, map),
+ : QuotaLimitHeuristic(
+ config,
+ map,
+ "MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES"),
callback_registered_(false),
weak_ptr_factory_(this) {}
virtual ~ClearCacheQuotaHeuristic() {}
@@ -1791,8 +1796,9 @@ bool WebRequestEventHandled::RunImpl() {
void WebRequestHandlerBehaviorChanged::GetQuotaLimitHeuristics(
QuotaLimitHeuristics* heuristics) const {
QuotaLimitHeuristic::Config config = {
- 20, // Refill 20 tokens per interval.
- base::TimeDelta::FromMinutes(10) // 10 minutes refill interval.
+ // See web_request.json for current value.
+ web_request::MAX_HANDLER_BEHAVIOR_CHANGED_CALLS_PER_10_MINUTES,
+ base::TimeDelta::FromMinutes(10)
};
QuotaLimitHeuristic::BucketMapper* bucket_mapper =
new QuotaLimitHeuristic::SingletonBucketMapper();
@@ -1801,7 +1807,8 @@ void WebRequestHandlerBehaviorChanged::GetQuotaLimitHeuristics(
heuristics->push_back(heuristic);
}
-void WebRequestHandlerBehaviorChanged::OnQuotaExceeded() {
+void WebRequestHandlerBehaviorChanged::OnQuotaExceeded(
+ const std::string& violation_error) {
// Post warning message.
std::set<std::string> extension_ids;
extension_ids.insert(extension_id());
diff --git a/chrome/browser/extensions/api/web_request/web_request_api.h b/chrome/browser/extensions/api/web_request/web_request_api.h
index f29d699..daecd20 100644
--- a/chrome/browser/extensions/api/web_request/web_request_api.h
+++ b/chrome/browser/extensions/api/web_request/web_request_api.h
@@ -437,7 +437,7 @@ class WebRequestHandlerBehaviorChanged : public SyncIOThreadExtensionFunction {
QuotaLimitHeuristics* heuristics) const OVERRIDE;
// Handle quota exceeded gracefully: Only warn the user but still execute the
// function.
- virtual void OnQuotaExceeded() OVERRIDE;
+ virtual void OnQuotaExceeded(const std::string& error) OVERRIDE;
virtual bool RunImpl() OVERRIDE;
};
diff --git a/chrome/browser/extensions/extension_function.cc b/chrome/browser/extensions/extension_function.cc
index e28e353..f75cf6ed 100644
--- a/chrome/browser/extensions/extension_function.cc
+++ b/chrome/browser/extensions/extension_function.cc
@@ -87,8 +87,8 @@ bool ExtensionFunction::HasPermission() {
return extension_->HasAPIPermission(name_);
}
-void ExtensionFunction::OnQuotaExceeded() {
- error_ = QuotaLimitHeuristic::kGenericOverQuotaError;
+void ExtensionFunction::OnQuotaExceeded(const std::string& violation_error) {
+ error_ = violation_error;
SendResponse(false);
}
diff --git a/chrome/browser/extensions/extension_function.h b/chrome/browser/extensions/extension_function.h
index adef96a..110d171 100644
--- a/chrome/browser/extensions/extension_function.h
+++ b/chrome/browser/extensions/extension_function.h
@@ -118,7 +118,7 @@ class ExtensionFunction
// Called when the quota limit has been exceeded. The default implementation
// returns an error.
- virtual void OnQuotaExceeded();
+ virtual void OnQuotaExceeded(const std::string& violation_error);
// Specifies the raw arguments to the function, as a JSON value.
virtual void SetArgs(const base::ListValue* args);
diff --git a/chrome/browser/extensions/extension_function_dispatcher.cc b/chrome/browser/extensions/extension_function_dispatcher.cc
index 566fd28..4ef84bd 100644
--- a/chrome/browser/extensions/extension_function_dispatcher.cc
+++ b/chrome/browser/extensions/extension_function_dispatcher.cc
@@ -152,12 +152,15 @@ void ExtensionFunctionDispatcher::DispatchOnIOThread(
extension_info_map->IsIncognitoEnabled(extension->id()));
ExtensionsQuotaService* quota = extension_info_map->GetQuotaService();
- if (quota->Assess(extension->id(), function, &params.arguments,
- base::TimeTicks::Now())) {
+ std::string violation_error = quota->Assess(extension->id(),
+ function,
+ &params.arguments,
+ base::TimeTicks::Now());
+ if (violation_error.empty()) {
function->Run();
LogSuccess(extension, params);
} else {
- function->OnQuotaExceeded();
+ function->OnQuotaExceeded(violation_error);
LogFailure(extension, params.name, kQuotaExceeded);
}
}
@@ -209,15 +212,18 @@ void ExtensionFunctionDispatcher::Dispatch(
function->set_include_incognito(service->CanCrossIncognito(extension));
ExtensionsQuotaService* quota = service->quota_service();
- if (quota->Assess(extension->id(), function, &params.arguments,
- base::TimeTicks::Now())) {
+ std::string violation_error = quota->Assess(extension->id(),
+ function,
+ &params.arguments,
+ base::TimeTicks::Now());
+ if (violation_error.empty()) {
// See crbug.com/39178.
ExternalProtocolHandler::PermitLaunchUrl();
function->Run();
LogSuccess(extension, params);
} else {
- function->OnQuotaExceeded();
+ function->OnQuotaExceeded(violation_error);
LogFailure(extension, params.name, kQuotaExceeded);
}
diff --git a/chrome/browser/extensions/extensions_quota_service.cc b/chrome/browser/extensions/extensions_quota_service.cc
index fd60d98..330a0b3 100644
--- a/chrome/browser/extensions/extensions_quota_service.cc
+++ b/chrome/browser/extensions/extensions_quota_service.cc
@@ -7,14 +7,18 @@
#include "base/message_loop.h"
#include "base/stl_util.h"
#include "chrome/browser/extensions/extension_function.h"
+#include "chrome/common/extensions/extension_error_utils.h"
+
+namespace {
// If the browser stays open long enough, we reset state once a day.
// Whatever this value is, it should be an order of magnitude longer than
// the longest interval in any of the QuotaLimitHeuristics in use.
-static const int kPurgeIntervalInDays = 1;
+const int kPurgeIntervalInDays = 1;
+
+const char kOverQuotaError[] = "This request exceeds the * quota.";
-const char QuotaLimitHeuristic::kGenericOverQuotaError[] =
- "This request exceeds available quota.";
+} // namespace
ExtensionsQuotaService::ExtensionsQuotaService() {
if (MessageLoop::current() != NULL) { // Null in unit tests.
@@ -30,13 +34,15 @@ ExtensionsQuotaService::~ExtensionsQuotaService() {
Purge();
}
-bool ExtensionsQuotaService::Assess(const std::string& extension_id,
- ExtensionFunction* function, const ListValue* args,
+std::string ExtensionsQuotaService::Assess(
+ const std::string& extension_id,
+ ExtensionFunction* function,
+ const ListValue* args,
const base::TimeTicks& event_time) {
DCHECK(CalledOnValidThread());
if (function->ShouldSkipQuotaLimiting())
- return true;
+ return "";
// Lookup function list for extension.
FunctionHeuristicsMap& functions = function_heuristics_[extension_id];
@@ -47,25 +53,33 @@ bool ExtensionsQuotaService::Assess(const std::string& extension_id,
function->GetQuotaLimitHeuristics(&heuristics);
if (heuristics.empty())
- return true; // No heuristic implies no limit.
+ return ""; // No heuristic implies no limit.
- if (violators_.find(extension_id) != violators_.end())
- return false; // Repeat offender.
+ ViolationErrorMap::iterator violation_error =
+ violation_errors_.find(extension_id);
+ if (violation_error != violation_errors_.end())
+ return violation_error->second; // Repeat offender.
- bool global_decision = true;
+ QuotaLimitHeuristic* failed_heuristic = NULL;
for (QuotaLimitHeuristics::iterator heuristic = heuristics.begin();
heuristic != heuristics.end(); ++heuristic) {
// Apply heuristic to each item (bucket).
- global_decision = (*heuristic)->ApplyToArgs(args, event_time) &&
- global_decision;
+ if (!(*heuristic)->ApplyToArgs(args, event_time)) {
+ failed_heuristic = *heuristic;
+ break;
+ }
}
- if (!global_decision) {
- PurgeFunctionHeuristicsMap(&functions);
- function_heuristics_.erase(extension_id);
- violators_.insert(extension_id);
- }
- return global_decision;
+ if (!failed_heuristic)
+ return "";
+
+ std::string error = failed_heuristic->GetError();
+ DCHECK_GT(error.length(), 0u);
+
+ PurgeFunctionHeuristicsMap(&functions);
+ function_heuristics_.erase(extension_id);
+ violation_errors_[extension_id] = error;
+ return error;
}
void ExtensionsQuotaService::PurgeFunctionHeuristicsMap(
@@ -98,8 +112,9 @@ void QuotaLimitHeuristic::SingletonBucketMapper::GetBucketsForArgs(
}
QuotaLimitHeuristic::QuotaLimitHeuristic(const Config& config,
- BucketMapper* map)
- : config_(config), bucket_mapper_(map) {
+ BucketMapper* map,
+ const std::string& name)
+ : config_(config), bucket_mapper_(map), name_(name) {
}
QuotaLimitHeuristic::~QuotaLimitHeuristic() {}
@@ -117,9 +132,16 @@ bool QuotaLimitHeuristic::ApplyToArgs(const ListValue* args,
return true;
}
+std::string QuotaLimitHeuristic::GetError() const {
+ return ExtensionErrorUtils::FormatErrorMessage(kOverQuotaError, name_);
+}
+
ExtensionsQuotaService::SustainedLimit::SustainedLimit(
- const base::TimeDelta& sustain, const Config& config, BucketMapper* map)
- : QuotaLimitHeuristic(config, map),
+ const base::TimeDelta& sustain,
+ const Config& config,
+ BucketMapper* map,
+ const std::string& name)
+ : QuotaLimitHeuristic(config, map, name),
repeat_exhaustion_allowance_(sustain.InSeconds() /
config.refill_interval.InSeconds()),
num_available_repeat_exhaustions_(repeat_exhaustion_allowance_) {
diff --git a/chrome/browser/extensions/extensions_quota_service.h b/chrome/browser/extensions/extensions_quota_service.h
index 6737044..5c3ce42 100644
--- a/chrome/browser/extensions/extensions_quota_service.h
+++ b/chrome/browser/extensions/extensions_quota_service.h
@@ -52,10 +52,13 @@ class ExtensionsQuotaService : public base::NonThreadSafe {
// Decide whether the invocation of |function| with argument |args| by the
// extension specified by |extension_id| results in a quota limit violation.
- // Returns true if the request is fine and can proceed, false if the request
- // should be throttled and an error returned to the extension.
- bool Assess(const std::string& extension_id, ExtensionFunction* function,
- const ListValue* args, const base::TimeTicks& event_time);
+ // Returns an error message representing the failure if quota was exceeded,
+ // or empty-string if the request is fine and can proceed.
+ std::string Assess(const std::string& extension_id,
+ ExtensionFunction* function,
+ const ListValue* args,
+ const base::TimeTicks& event_time);
+
private:
friend class extensions::TestResetQuotaFunction;
typedef std::string ExtensionId;
@@ -63,12 +66,12 @@ class ExtensionsQuotaService : public base::NonThreadSafe {
// All QuotaLimitHeuristic instances in this map are owned by us.
typedef std::map<FunctionName, QuotaLimitHeuristics> FunctionHeuristicsMap;
- // Purge resets all accumulated data (except |violators_|) as if the service
- // was just created. Called periodically so we don't consume an unbounded
- // amount of memory while tracking quota. Yes, this could mean an extension
- // gets away with murder if it is timed right, but the extensions we are
- // trying to limit are ones that consistently violate, so we'll converge
- // to the correct set.
+ // Purge resets all accumulated data (except |violation_errors_|) as if the
+ // service was just created. Called periodically so we don't consume an
+ // unbounded amount of memory while tracking quota. Yes, this could mean an
+ // extension gets away with murder if it is timed right, but the extensions
+ // we are trying to limit are ones that consistently violate, so we'll
+ // converge to the correct set.
void Purge();
void PurgeFunctionHeuristicsMap(FunctionHeuristicsMap* map);
base::RepeatingTimer<ExtensionsQuotaService> purge_timer_;
@@ -83,7 +86,8 @@ class ExtensionsQuotaService : public base::NonThreadSafe {
// For now, as soon as an extension violates quota, we don't allow it to
// make any more requests to quota limited functions. This provides a quick
// lookup for these extensions that is only stored in memory.
- base::hash_set<std::string> violators_;
+ typedef std::map<std::string, std::string> ViolationErrorMap;
+ ViolationErrorMap violation_errors_;
DISALLOW_COPY_AND_ASSIGN(ExtensionsQuotaService);
};
@@ -137,9 +141,6 @@ class QuotaLimitHeuristic {
};
typedef std::list<Bucket*> BucketList;
- // A generic error message for quota violating requests.
- static const char kGenericOverQuotaError[];
-
// A helper interface to retrieve the bucket corresponding to |args| from
// the set of buckets (which is typically stored in the BucketMapper itself)
// for this QuotaLimitHeuristic.
@@ -169,8 +170,10 @@ class QuotaLimitHeuristic {
DISALLOW_COPY_AND_ASSIGN(SingletonBucketMapper);
};
- // Ownership of |mapper| is given to the new QuotaLimitHeuristic.
- QuotaLimitHeuristic(const Config& config, BucketMapper* map);
+ // Ownership of |map| is given to the new QuotaLimitHeuristic.
+ QuotaLimitHeuristic(const Config& config,
+ BucketMapper* map,
+ const std::string& name);
virtual ~QuotaLimitHeuristic();
// Determines if sufficient quota exists (according to the Apply
@@ -179,6 +182,9 @@ class QuotaLimitHeuristic {
// is retrieved using the BucketMapper).
bool ApplyToArgs(const ListValue* args, const base::TimeTicks& event_time);
+ // Returns an error formatted according to this heuristic.
+ std::string GetError() const;
+
protected:
const Config& config() { return config_; }
@@ -191,9 +197,12 @@ class QuotaLimitHeuristic {
const Config config_;
- // The mapper used in Map. Cannot be NULL.
+ // The mapper used in Map. Cannot be NULL.
scoped_ptr<BucketMapper> bucket_mapper_;
+ // The name of the heuristic for formatting error messages.
+ std::string name_;
+
DISALLOW_COPY_AND_ASSIGN(QuotaLimitHeuristic);
};
@@ -201,8 +210,8 @@ class QuotaLimitHeuristic {
// a given period of time; e.g "no more than 100 events in an hour".
class ExtensionsQuotaService::TimedLimit : public QuotaLimitHeuristic {
public:
- TimedLimit(const Config& config, BucketMapper* map)
- : QuotaLimitHeuristic(config, map) {}
+ TimedLimit(const Config& config, BucketMapper* map, const std::string& name)
+ : QuotaLimitHeuristic(config, map, name) {}
virtual bool Apply(Bucket* bucket,
const base::TimeTicks& event_time) OVERRIDE;
};
@@ -214,7 +223,8 @@ class ExtensionsQuotaService::SustainedLimit : public QuotaLimitHeuristic {
public:
SustainedLimit(const base::TimeDelta& sustain,
const Config& config,
- BucketMapper* map);
+ BucketMapper* map,
+ const std::string& name);
virtual bool Apply(Bucket* bucket,
const base::TimeTicks& event_time) OVERRIDE;
private:
diff --git a/chrome/browser/extensions/extensions_quota_service_unittest.cc b/chrome/browser/extensions/extensions_quota_service_unittest.cc
index 96cfdb7..8dd7d22 100644
--- a/chrome/browser/extensions/extensions_quota_service_unittest.cc
+++ b/chrome/browser/extensions/extensions_quota_service_unittest.cc
@@ -21,14 +21,15 @@ typedef QuotaLimitHeuristic::BucketList BucketList;
typedef ExtensionsQuotaService::TimedLimit TimedLimit;
typedef ExtensionsQuotaService::SustainedLimit SustainedLimit;
-static const Config kFrozenConfig = { 0, TimeDelta::FromDays(0) };
-static const Config k2PerMinute = { 2, TimeDelta::FromMinutes(1) };
-static const Config k20PerHour = { 20, TimeDelta::FromHours(1) };
-static const TimeTicks kStartTime = TimeTicks();
-static const TimeTicks k1MinuteAfterStart =
- kStartTime + TimeDelta::FromMinutes(1);
-
namespace {
+
+const char kGenericName[] = "name";
+const Config kFrozenConfig = { 0, TimeDelta::FromDays(0) };
+const Config k2PerMinute = { 2, TimeDelta::FromMinutes(1) };
+const Config k20PerHour = { 20, TimeDelta::FromHours(1) };
+const TimeTicks kStartTime = TimeTicks();
+const TimeTicks k1MinuteAfterStart = kStartTime + TimeDelta::FromMinutes(1);
+
class Mapper : public QuotaLimitHeuristic::BucketMapper {
public:
Mapper() {}
@@ -75,7 +76,8 @@ class TimedLimitMockFunction : public MockFunction {
: MockFunction(name) {}
virtual void GetQuotaLimitHeuristics(
QuotaLimitHeuristics* heuristics) const {
- heuristics->push_back(new TimedLimit(k2PerMinute, new Mapper()));
+ heuristics->push_back(
+ new TimedLimit(k2PerMinute, new Mapper(), kGenericName));
}
private:
@@ -89,10 +91,11 @@ class ChainedLimitsMockFunction : public MockFunction {
virtual void GetQuotaLimitHeuristics(
QuotaLimitHeuristics* heuristics) const {
// No more than 2 per minute sustained over 5 minutes.
- heuristics->push_back(new SustainedLimit(TimeDelta::FromMinutes(5),
- k2PerMinute, new Mapper()));
+ heuristics->push_back(new SustainedLimit(
+ TimeDelta::FromMinutes(5), k2PerMinute, new Mapper(), kGenericName));
// No more than 20 per hour.
- heuristics->push_back(new TimedLimit(k20PerHour, new Mapper()));
+ heuristics->push_back(
+ new TimedLimit(k20PerHour, new Mapper(), kGenericName));
}
private:
@@ -104,7 +107,8 @@ class FrozenMockFunction : public MockFunction {
explicit FrozenMockFunction(const std::string& name) : MockFunction(name) {}
virtual void GetQuotaLimitHeuristics(
QuotaLimitHeuristics* heuristics) const {
- heuristics->push_back(new TimedLimit(kFrozenConfig, new Mapper()));
+ heuristics->push_back(
+ new TimedLimit(kFrozenConfig, new Mapper(), kGenericName));
}
private:
@@ -165,7 +169,7 @@ class QuotaLimitHeuristicTest : public testing::Test {
};
TEST_F(QuotaLimitHeuristicTest, Timed) {
- TimedLimit lim(k2PerMinute, new MockMapper());
+ TimedLimit lim(k2PerMinute, new MockMapper(), kGenericName);
Bucket b;
b.Reset(k2PerMinute, kStartTime);
@@ -184,7 +188,8 @@ TEST_F(QuotaLimitHeuristicTest, Timed) {
}
TEST_F(QuotaLimitHeuristicTest, Sustained) {
- SustainedLimit lim(TimeDelta::FromMinutes(5), k2PerMinute, new MockMapper());
+ SustainedLimit lim(
+ TimeDelta::FromMinutes(5), k2PerMinute, new MockMapper(), kGenericName);
Bucket bucket;
bucket.Reset(k2PerMinute, kStartTime);
@@ -210,54 +215,55 @@ TEST_F(QuotaLimitHeuristicTest, Sustained) {
TEST_F(ExtensionsQuotaServiceTest, NoHeuristic) {
scoped_refptr<MockFunction> f(new MockFunction("foo"));
ListValue args;
- EXPECT_TRUE(service_->Assess(extension_a_, f, &args, kStartTime));
+ EXPECT_EQ("", service_->Assess(extension_a_, f, &args, kStartTime));
}
TEST_F(ExtensionsQuotaServiceTest, FrozenHeuristic) {
scoped_refptr<MockFunction> f(new FrozenMockFunction("foo"));
ListValue args;
args.Append(new base::FundamentalValue(1));
- EXPECT_FALSE(service_->Assess(extension_a_, f, &args, kStartTime));
+ EXPECT_NE("", service_->Assess(extension_a_, f, &args, kStartTime));
}
TEST_F(ExtensionsQuotaServiceTest, SingleHeuristic) {
scoped_refptr<MockFunction> f(new TimedLimitMockFunction("foo"));
ListValue args;
args.Append(new base::FundamentalValue(1));
- EXPECT_TRUE(service_->Assess(extension_a_, f, &args, kStartTime));
- EXPECT_TRUE(service_->Assess(extension_a_, f, &args,
- kStartTime + TimeDelta::FromSeconds(10)));
- EXPECT_FALSE(service_->Assess(extension_a_, f, &args,
+ EXPECT_EQ("", service_->Assess(extension_a_, f, &args, kStartTime));
+ EXPECT_EQ("", service_->Assess(extension_a_, f, &args,
+ kStartTime + TimeDelta::FromSeconds(10)));
+ EXPECT_NE("", service_->Assess(extension_a_, f, &args,
kStartTime + TimeDelta::FromSeconds(15)));
ListValue args2;
args2.Append(new base::FundamentalValue(1));
args2.Append(new base::FundamentalValue(2));
- EXPECT_TRUE(service_->Assess(extension_b_, f, &args2, kStartTime));
- EXPECT_TRUE(service_->Assess(extension_b_, f, &args2,
- kStartTime + TimeDelta::FromSeconds(10)));
+ EXPECT_EQ("", service_->Assess(extension_b_, f, &args2, kStartTime));
+ EXPECT_EQ("", service_->Assess(extension_b_, f, &args2,
+ kStartTime + TimeDelta::FromSeconds(10)));
TimeDelta peace = TimeDelta::FromMinutes(30);
- EXPECT_TRUE(service_->Assess(extension_b_, f, &args, kStartTime + peace));
- EXPECT_TRUE(service_->Assess(extension_b_, f, &args,
- kStartTime + peace + TimeDelta::FromSeconds(10)));
- EXPECT_FALSE(service_->Assess(extension_b_, f, &args2,
+ EXPECT_EQ("", service_->Assess(extension_b_, f, &args, kStartTime + peace));
+ EXPECT_EQ("", service_->Assess(
+ extension_b_, f, &args,
+ kStartTime + peace + TimeDelta::FromSeconds(10)));
+ EXPECT_NE("", service_->Assess(extension_b_, f, &args2,
kStartTime + peace + TimeDelta::FromSeconds(15)));
// Test that items are independent.
ListValue args3;
args3.Append(new base::FundamentalValue(3));
- EXPECT_TRUE(service_->Assess(extension_c_, f, &args, kStartTime));
- EXPECT_TRUE(service_->Assess(extension_c_, f, &args3,
- kStartTime + TimeDelta::FromSeconds(10)));
- EXPECT_TRUE(service_->Assess(extension_c_, f, &args,
- kStartTime + TimeDelta::FromSeconds(15)));
- EXPECT_TRUE(service_->Assess(extension_c_, f, &args3,
- kStartTime + TimeDelta::FromSeconds(20)));
- EXPECT_FALSE(service_->Assess(extension_c_, f, &args,
- kStartTime + TimeDelta::FromSeconds(25)));
- EXPECT_FALSE(service_->Assess(extension_c_, f, &args3,
- kStartTime + TimeDelta::FromSeconds(30)));
+ EXPECT_EQ("", service_->Assess(extension_c_, f, &args, kStartTime));
+ EXPECT_EQ("", service_->Assess(extension_c_, f, &args3,
+ kStartTime + TimeDelta::FromSeconds(10)));
+ EXPECT_EQ("", service_->Assess(extension_c_, f, &args,
+ kStartTime + TimeDelta::FromSeconds(15)));
+ EXPECT_EQ("", service_->Assess(extension_c_, f, &args3,
+ kStartTime + TimeDelta::FromSeconds(20)));
+ EXPECT_NE("", service_->Assess(extension_c_, f, &args,
+ kStartTime + TimeDelta::FromSeconds(25)));
+ EXPECT_NE("", service_->Assess(extension_c_, f, &args3,
+ kStartTime + TimeDelta::FromSeconds(30)));
}
TEST_F(ExtensionsQuotaServiceTest, ChainedHeuristics) {
@@ -269,25 +275,29 @@ TEST_F(ExtensionsQuotaServiceTest, ChainedHeuristics) {
// One event per minute for 20 minutes comes in under the sustained limit,
// but is equal to the timed limit.
for (int i = 0; i < 20; i++) {
- EXPECT_TRUE(service_->Assess(extension_a_, f, &args,
- kStartTime + TimeDelta::FromSeconds(10 + i * 60)));
+ EXPECT_EQ("", service_->Assess(
+ extension_a_, f, &args,
+ kStartTime + TimeDelta::FromSeconds(10 + i * 60)));
}
// This will bring us to 21 events in an hour, which is a violation.
- EXPECT_FALSE(service_->Assess(extension_a_, f, &args,
- kStartTime + TimeDelta::FromMinutes(30)));
+ EXPECT_NE("", service_->Assess(extension_a_, f, &args,
+ kStartTime + TimeDelta::FromMinutes(30)));
// Now, check that we can still hit the lower limit.
for (int i = 0; i < 5; i++) {
- EXPECT_TRUE(service_->Assess(extension_b_, f, &args,
- kStartTime + TimeDelta::FromSeconds(10 + i * 60)));
- EXPECT_TRUE(service_->Assess(extension_b_, f, &args,
- kStartTime + TimeDelta::FromSeconds(15 + i * 60)));
- EXPECT_TRUE(service_->Assess(extension_b_, f, &args,
- kStartTime + TimeDelta::FromSeconds(20 + i * 60)));
+ EXPECT_EQ("", service_->Assess(
+ extension_b_, f, &args,
+ kStartTime + TimeDelta::FromSeconds(10 + i * 60)));
+ EXPECT_EQ("", service_->Assess(
+ extension_b_, f, &args,
+ kStartTime + TimeDelta::FromSeconds(15 + i * 60)));
+ EXPECT_EQ("", service_->Assess(
+ extension_b_, f, &args,
+ kStartTime + TimeDelta::FromSeconds(20 + i * 60)));
}
- EXPECT_FALSE(service_->Assess(extension_b_, f, &args,
+ EXPECT_NE("", service_->Assess(extension_b_, f, &args,
kStartTime + TimeDelta::FromMinutes(6)));
}
@@ -300,16 +310,16 @@ TEST_F(ExtensionsQuotaServiceTest, MultipleFunctionsDontInterfere) {
args_f.Append(new base::FundamentalValue(1));
args_g.Append(new base::FundamentalValue(2));
- EXPECT_TRUE(service_->Assess(extension_a_, f, &args_f, kStartTime));
- EXPECT_TRUE(service_->Assess(extension_a_, g, &args_g, kStartTime));
- EXPECT_TRUE(service_->Assess(extension_a_, f, &args_f,
- kStartTime + TimeDelta::FromSeconds(10)));
- EXPECT_TRUE(service_->Assess(extension_a_, g, &args_g,
- kStartTime + TimeDelta::FromSeconds(10)));
- EXPECT_FALSE(service_->Assess(extension_a_, f, &args_f,
- kStartTime + TimeDelta::FromSeconds(15)));
- EXPECT_FALSE(service_->Assess(extension_a_, g, &args_g,
- kStartTime + TimeDelta::FromSeconds(15)));
+ EXPECT_EQ("", service_->Assess(extension_a_, f, &args_f, kStartTime));
+ EXPECT_EQ("", service_->Assess(extension_a_, g, &args_g, kStartTime));
+ EXPECT_EQ("", service_->Assess(extension_a_, f, &args_f,
+ kStartTime + TimeDelta::FromSeconds(10)));
+ EXPECT_EQ("", service_->Assess(extension_a_, g, &args_g,
+ kStartTime + TimeDelta::FromSeconds(10)));
+ EXPECT_NE("", service_->Assess(extension_a_, f, &args_f,
+ kStartTime + TimeDelta::FromSeconds(15)));
+ EXPECT_NE("", service_->Assess(extension_a_, g, &args_g,
+ kStartTime + TimeDelta::FromSeconds(15)));
}
TEST_F(ExtensionsQuotaServiceTest, ViolatorsWillBeViolators) {
@@ -317,16 +327,16 @@ TEST_F(ExtensionsQuotaServiceTest, ViolatorsWillBeViolators) {
scoped_refptr<MockFunction> g(new TimedLimitMockFunction("bar"));
ListValue arg;
arg.Append(new base::FundamentalValue(1));
- EXPECT_TRUE(service_->Assess(extension_a_, f, &arg, kStartTime));
- EXPECT_TRUE(service_->Assess(extension_a_, f, &arg,
- kStartTime + TimeDelta::FromSeconds(10)));
- EXPECT_FALSE(service_->Assess(extension_a_, f, &arg,
- kStartTime + TimeDelta::FromSeconds(15)));
+ EXPECT_EQ("", service_->Assess(extension_a_, f, &arg, kStartTime));
+ EXPECT_EQ("", service_->Assess(extension_a_, f, &arg,
+ kStartTime + TimeDelta::FromSeconds(10)));
+ EXPECT_NE("", service_->Assess(extension_a_, f, &arg,
+ kStartTime + TimeDelta::FromSeconds(15)));
// We don't allow this extension to use quota limited functions even if they
// wait a while.
- EXPECT_FALSE(service_->Assess(extension_a_, f, &arg,
- kStartTime + TimeDelta::FromDays(1)));
- EXPECT_FALSE(service_->Assess(extension_a_, g, &arg,
- kStartTime + TimeDelta::FromDays(1)));
+ EXPECT_NE("", service_->Assess(extension_a_, f, &arg,
+ kStartTime + TimeDelta::FromDays(1)));
+ EXPECT_NE("", service_->Assess(extension_a_, g, &arg,
+ kStartTime + TimeDelta::FromDays(1)));
}
diff --git a/chrome/browser/extensions/settings/settings_api.cc b/chrome/browser/extensions/settings/settings_api.cc
index 7cf459a..d808f19 100644
--- a/chrome/browser/extensions/settings/settings_api.cc
+++ b/chrome/browser/extensions/settings/settings_api.cc
@@ -154,7 +154,9 @@ void GetModificationQuotaLimitHeuristics(QuotaLimitHeuristics* heuristics) {
};
heuristics->push_back(
new ExtensionsQuotaService::TimedLimit(
- longLimitConfig, new QuotaLimitHeuristic::SingletonBucketMapper()));
+ longLimitConfig,
+ new QuotaLimitHeuristic::SingletonBucketMapper(),
+ "MAX_WRITE_OPERATIONS_PER_HOUR"));
// A max of 10 operations per minute, sustained over 10 minutes.
QuotaLimitHeuristic::Config shortLimitConfig = {
@@ -166,7 +168,8 @@ void GetModificationQuotaLimitHeuristics(QuotaLimitHeuristics* heuristics) {
new ExtensionsQuotaService::SustainedLimit(
base::TimeDelta::FromMinutes(10),
shortLimitConfig,
- new QuotaLimitHeuristic::SingletonBucketMapper()));
+ new QuotaLimitHeuristic::SingletonBucketMapper(),
+ "MAX_SUSTAINED_WRITE_OPERATIONS_PER_MINUTE"));
};
} // namespace
diff --git a/chrome/browser/extensions/settings/settings_storage_quota_enforcer.cc b/chrome/browser/extensions/settings/settings_storage_quota_enforcer.cc
index 5fef45e..9057d39 100644
--- a/chrome/browser/extensions/settings/settings_storage_quota_enforcer.cc
+++ b/chrome/browser/extensions/settings/settings_storage_quota_enforcer.cc
@@ -10,12 +10,13 @@
#include "base/message_loop.h"
#include "base/metrics/histogram.h"
#include "chrome/common/extensions/api/extension_api.h"
+#include "chrome/common/extensions/extension_error_utils.h"
namespace extensions {
namespace {
-const char* kExceededQuotaErrorMessage = "Quota exceeded";
+const char* kQuotaExceededError = "* quota exceeded.";
// Resources there are a quota for.
enum Resource {
@@ -54,23 +55,28 @@ void Free(
// Returns an error result and logs the quota exceeded to UMA.
ValueStore::WriteResult QuotaExceededFor(Resource resource) {
+ std::string name;
switch (resource) {
case QUOTA_BYTES:
+ name = "QUOTA_BYTES";
UMA_HISTOGRAM_COUNTS_100(
"Extensions.SettingsQuotaExceeded.TotalBytes", 1);
break;
case QUOTA_BYTES_PER_ITEM:
+ name = "QUOTA_BYTES_PER_ITEM";
UMA_HISTOGRAM_COUNTS_100(
"Extensions.SettingsQuotaExceeded.BytesPerSetting", 1);
break;
case MAX_ITEMS:
+ name = "MAX_ITEMS";
UMA_HISTOGRAM_COUNTS_100(
"Extensions.SettingsQuotaExceeded.KeyCount", 1);
break;
default:
NOTREACHED();
}
- return ValueStore::MakeWriteResult(kExceededQuotaErrorMessage);
+ return ValueStore::MakeWriteResult(
+ ExtensionErrorUtils::FormatErrorMessage(kQuotaExceededError, name));
}
} // namespace