1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "extensions/browser/quota_service.h"
7 #include "base/message_loop/message_loop.h"
8 #include "base/stl_util.h"
9 #include "extensions/browser/extension_function.h"
10 #include "extensions/common/error_utils.h"
14 // If the browser stays open long enough, we reset state once a day.
15 // Whatever this value is, it should be an order of magnitude longer than
16 // the longest interval in any of the QuotaLimitHeuristics in use.
17 const int kPurgeIntervalInDays
= 1;
19 const char kOverQuotaError
[] = "This request exceeds the * quota.";
23 namespace extensions
{
25 QuotaService::QuotaService() {
26 if (base::MessageLoop::current() != NULL
) { // Null in unit tests.
27 purge_timer_
.Start(FROM_HERE
,
28 base::TimeDelta::FromDays(kPurgeIntervalInDays
),
30 &QuotaService::Purge
);
34 QuotaService::~QuotaService() {
35 DCHECK(CalledOnValidThread());
40 std::string
QuotaService::Assess(const std::string
& extension_id
,
41 ExtensionFunction
* function
,
42 const base::ListValue
* args
,
43 const base::TimeTicks
& event_time
) {
44 DCHECK(CalledOnValidThread());
46 if (function
->ShouldSkipQuotaLimiting())
49 // Lookup function list for extension.
50 FunctionHeuristicsMap
& functions
= function_heuristics_
[extension_id
];
52 // Lookup heuristics for function, create if necessary.
53 QuotaLimitHeuristics
& heuristics
= functions
[function
->name()];
54 if (heuristics
.empty())
55 function
->GetQuotaLimitHeuristics(&heuristics
);
57 if (heuristics
.empty())
58 return std::string(); // No heuristic implies no limit.
60 QuotaLimitHeuristic
* failed_heuristic
= NULL
;
61 for (QuotaLimitHeuristics::iterator heuristic
= heuristics
.begin();
62 heuristic
!= heuristics
.end();
64 // Apply heuristic to each item (bucket).
65 if (!(*heuristic
)->ApplyToArgs(args
, event_time
)) {
66 failed_heuristic
= *heuristic
;
71 if (!failed_heuristic
)
74 std::string error
= failed_heuristic
->GetError();
75 DCHECK_GT(error
.length(), 0u);
79 void QuotaService::PurgeFunctionHeuristicsMap(FunctionHeuristicsMap
* map
) {
80 FunctionHeuristicsMap::iterator heuristics
= map
->begin();
81 while (heuristics
!= map
->end()) {
82 STLDeleteElements(&heuristics
->second
);
83 map
->erase(heuristics
++);
87 void QuotaService::Purge() {
88 DCHECK(CalledOnValidThread());
89 std::map
<std::string
, FunctionHeuristicsMap
>::iterator it
=
90 function_heuristics_
.begin();
91 for (; it
!= function_heuristics_
.end(); function_heuristics_
.erase(it
++))
92 PurgeFunctionHeuristicsMap(&it
->second
);
95 void QuotaLimitHeuristic::Bucket::Reset(const Config
& config
,
96 const base::TimeTicks
& start
) {
97 num_tokens_
= config
.refill_token_count
;
98 expiration_
= start
+ config
.refill_interval
;
101 void QuotaLimitHeuristic::SingletonBucketMapper::GetBucketsForArgs(
102 const base::ListValue
* args
,
103 BucketList
* buckets
) {
104 buckets
->push_back(&bucket_
);
107 QuotaLimitHeuristic::QuotaLimitHeuristic(const Config
& config
,
109 const std::string
& name
)
110 : config_(config
), bucket_mapper_(map
), name_(name
) {}
112 QuotaLimitHeuristic::~QuotaLimitHeuristic() {}
114 bool QuotaLimitHeuristic::ApplyToArgs(const base::ListValue
* args
,
115 const base::TimeTicks
& event_time
) {
117 bucket_mapper_
->GetBucketsForArgs(args
, &buckets
);
118 for (BucketList::iterator i
= buckets
.begin(); i
!= buckets
.end(); ++i
) {
119 if ((*i
)->expiration().is_null()) // A brand new bucket.
120 (*i
)->Reset(config_
, event_time
);
121 if (!Apply(*i
, event_time
))
122 return false; // It only takes one to spoil it for everyone.
127 std::string
QuotaLimitHeuristic::GetError() const {
128 return extensions::ErrorUtils::FormatErrorMessage(kOverQuotaError
, name_
);
131 bool QuotaService::TimedLimit::Apply(Bucket
* bucket
,
132 const base::TimeTicks
& event_time
) {
133 if (event_time
> bucket
->expiration())
134 bucket
->Reset(config(), event_time
);
136 return bucket
->DeductToken();
139 } // namespace extensions