| Index: chrome/browser/extensions/extensions_quota_service.cc
|
| diff --git a/chrome/browser/extensions/extensions_quota_service.cc b/chrome/browser/extensions/extensions_quota_service.cc
|
| deleted file mode 100644
|
| index 830c93ad19d78cefae40cdaaeea4a90218b240a6..0000000000000000000000000000000000000000
|
| --- a/chrome/browser/extensions/extensions_quota_service.cc
|
| +++ /dev/null
|
| @@ -1,191 +0,0 @@
|
| -// Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| -// Use of this source code is governed by a BSD-style license that can be
|
| -// found in the LICENSE file.
|
| -
|
| -#include "chrome/browser/extensions/extensions_quota_service.h"
|
| -
|
| -#include "base/message_loop/message_loop.h"
|
| -#include "base/stl_util.h"
|
| -#include "chrome/browser/extensions/extension_function.h"
|
| -#include "extensions/common/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.
|
| -const int kPurgeIntervalInDays = 1;
|
| -
|
| -const char kOverQuotaError[] = "This request exceeds the * quota.";
|
| -
|
| -} // namespace
|
| -
|
| -ExtensionsQuotaService::ExtensionsQuotaService() {
|
| - if (base::MessageLoop::current() != NULL) { // Null in unit tests.
|
| - purge_timer_.Start(FROM_HERE,
|
| - base::TimeDelta::FromDays(kPurgeIntervalInDays),
|
| - this, &ExtensionsQuotaService::Purge);
|
| - }
|
| -}
|
| -
|
| -ExtensionsQuotaService::~ExtensionsQuotaService() {
|
| - DCHECK(CalledOnValidThread());
|
| - purge_timer_.Stop();
|
| - Purge();
|
| -}
|
| -
|
| -std::string ExtensionsQuotaService::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();
|
| -
|
| - // Lookup function list for extension.
|
| - FunctionHeuristicsMap& functions = function_heuristics_[extension_id];
|
| -
|
| - // Lookup heuristics for function, create if necessary.
|
| - QuotaLimitHeuristics& heuristics = functions[function->name()];
|
| - if (heuristics.empty())
|
| - function->GetQuotaLimitHeuristics(&heuristics);
|
| -
|
| - if (heuristics.empty())
|
| - return std::string(); // No heuristic implies no limit.
|
| -
|
| - ViolationErrorMap::iterator violation_error =
|
| - violation_errors_.find(extension_id);
|
| - if (violation_error != violation_errors_.end())
|
| - return violation_error->second; // Repeat offender.
|
| -
|
| - QuotaLimitHeuristic* failed_heuristic = NULL;
|
| - for (QuotaLimitHeuristics::iterator heuristic = heuristics.begin();
|
| - heuristic != heuristics.end(); ++heuristic) {
|
| - // Apply heuristic to each item (bucket).
|
| - 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 ExtensionsQuotaService::PurgeFunctionHeuristicsMap(
|
| - FunctionHeuristicsMap* map) {
|
| - FunctionHeuristicsMap::iterator heuristics = map->begin();
|
| - while (heuristics != map->end()) {
|
| - STLDeleteElements(&heuristics->second);
|
| - map->erase(heuristics++);
|
| - }
|
| -}
|
| -
|
| -void ExtensionsQuotaService::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()) // A brand new bucket.
|
| - (*i)->Reset(config_, event_time);
|
| - if (!Apply(*i, event_time))
|
| - return false; // It only takes one to spoil it for everyone.
|
| - }
|
| - return true;
|
| -}
|
| -
|
| -std::string QuotaLimitHeuristic::GetError() const {
|
| - return extensions::ErrorUtils::FormatErrorMessage(kOverQuotaError, name_);
|
| -}
|
| -
|
| -ExtensionsQuotaService::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 ExtensionsQuotaService::TimedLimit::Apply(Bucket* bucket,
|
| - const base::TimeTicks& event_time) {
|
| - if (event_time > bucket->expiration())
|
| - bucket->Reset(config(), event_time);
|
| -
|
| - return bucket->DeductToken();
|
| -}
|
| -
|
| -bool ExtensionsQuotaService::SustainedLimit::Apply(Bucket* bucket,
|
| - const base::TimeTicks& event_time) {
|
| - if (event_time > bucket->expiration()) {
|
| - // We reset state for this item and start over again if this request breaks
|
| - // the bad cycle that was previously being tracked. This occurs if the
|
| - // state in the bucket expired recently (it has been long enough since the
|
| - // event that we don't care about the last event), but the bucket still has
|
| - // tokens (so pressure was not sustained over that time), OR we are more
|
| - // than 1 full refill interval away from the last event (so even if we used
|
| - // up all the tokens in the last bucket, nothing happened in the entire
|
| - // next refill interval, so it doesn't matter).
|
| - 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) {
|
| - // The last interval was saturated with requests, and this is the first
|
| - // event in the next interval. If this happens
|
| - // repeat_exhaustion_allowance_ times, it's a violation. Reset the bucket
|
| - // state to start timing from the end of the last interval (and we'll
|
| - // deduct the token below) so we can detect this each time it happens.
|
| - bucket->Reset(config(), bucket->expiration());
|
| - } else {
|
| - // No allowances left; this request is a violation.
|
| - return false;
|
| - }
|
| - }
|
| -
|
| - // We can go negative since we check has_tokens when we get to *next* bucket,
|
| - // and for the small interval all that matters is whether we used up all the
|
| - // tokens (which is true if num_tokens_ <= 0).
|
| - bucket->DeductToken();
|
| - return true;
|
| -}
|
|
|