This source file includes following definitions.
- Assess
- PurgeFunctionHeuristicsMap
- Purge
- Reset
- GetBucketsForArgs
- name_
- ApplyToArgs
- GetError
- num_available_repeat_exhaustions_
- Apply
- Apply
#include "extensions/browser/quota_service.h"
#include "base/message_loop/message_loop.h"
#include "base/stl_util.h"
#include "extensions/browser/extension_function.h"
#include "extensions/common/error_utils.h"
namespace {
const int kPurgeIntervalInDays = 1;
const char kOverQuotaError[] = "This request exceeds the * quota.";
}
namespace extensions {
QuotaService::QuotaService() {
if (base::MessageLoop::current() != NULL) {
purge_timer_.Start(FROM_HERE,
base::TimeDelta::FromDays(kPurgeIntervalInDays),
this,
&QuotaService::Purge);
}
}
QuotaService::~QuotaService() {
DCHECK(CalledOnValidThread());
purge_timer_.Stop();
Purge();
}
std::string QuotaService::Assess(const std::string& extension_id,
ExtensionFunction* function,
const base::ListValue* args,
const base::TimeTicks& event_time) {
DCHECK(CalledOnValidThread());
if (function->ShouldSkipQuotaLimiting())
return std::string();
FunctionHeuristicsMap& functions = function_heuristics_[extension_id];
QuotaLimitHeuristics& heuristics = functions[function->name()];
if (heuristics.empty())
function->GetQuotaLimitHeuristics(&heuristics);
if (heuristics.empty())
return std::string();
ViolationErrorMap::iterator violation_error =
violation_errors_.find(extension_id);
if (violation_error != violation_errors_.end())
return violation_error->second;
QuotaLimitHeuristic* failed_heuristic = NULL;
for (QuotaLimitHeuristics::iterator heuristic = heuristics.begin();
heuristic != heuristics.end();
++heuristic) {
if (!(*heuristic)->ApplyToArgs(args, event_time)) {
failed_heuristic = *heuristic;
break;
}
}
if (!failed_heuristic)
return std::string();
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 QuotaService::PurgeFunctionHeuristicsMap(FunctionHeuristicsMap* map) {
FunctionHeuristicsMap::iterator heuristics = map->begin();
while (heuristics != map->end()) {
STLDeleteElements(&heuristics->second);
map->erase(heuristics++);
}
}
void QuotaService::Purge() {
DCHECK(CalledOnValidThread());
std::map<std::string, FunctionHeuristicsMap>::iterator it =
function_heuristics_.begin();
for (; it != function_heuristics_.end(); function_heuristics_.erase(it++))
PurgeFunctionHeuristicsMap(&it->second);
}
void QuotaLimitHeuristic::Bucket::Reset(const Config& config,
const base::TimeTicks& start) {
num_tokens_ = config.refill_token_count;
expiration_ = start + config.refill_interval;
}
void QuotaLimitHeuristic::SingletonBucketMapper::GetBucketsForArgs(
const base::ListValue* args,
BucketList* buckets) {
buckets->push_back(&bucket_);
}
QuotaLimitHeuristic::QuotaLimitHeuristic(const Config& config,
BucketMapper* map,
const std::string& name)
: config_(config), bucket_mapper_(map), name_(name) {}
QuotaLimitHeuristic::~QuotaLimitHeuristic() {}
bool QuotaLimitHeuristic::ApplyToArgs(const base::ListValue* args,
const base::TimeTicks& event_time) {
BucketList buckets;
bucket_mapper_->GetBucketsForArgs(args, &buckets);
for (BucketList::iterator i = buckets.begin(); i != buckets.end(); ++i) {
if ((*i)->expiration().is_null())
(*i)->Reset(config_, event_time);
if (!Apply(*i, event_time))
return false;
}
return true;
}
std::string QuotaLimitHeuristic::GetError() const {
return extensions::ErrorUtils::FormatErrorMessage(kOverQuotaError, name_);
}
QuotaService::SustainedLimit::SustainedLimit(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_) {}
bool QuotaService::TimedLimit::Apply(Bucket* bucket,
const base::TimeTicks& event_time) {
if (event_time > bucket->expiration())
bucket->Reset(config(), event_time);
return bucket->DeductToken();
}
bool QuotaService::SustainedLimit::Apply(Bucket* bucket,
const base::TimeTicks& event_time) {
if (event_time > bucket->expiration()) {
if (bucket->has_tokens() ||
event_time > bucket->expiration() + config().refill_interval) {
bucket->Reset(config(), event_time);
num_available_repeat_exhaustions_ = repeat_exhaustion_allowance_;
} else if (--num_available_repeat_exhaustions_ > 0) {
bucket->Reset(config(), bucket->expiration());
} else {
return false;
}
}
bucket->DeductToken();
return true;
}
}