| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // The ExtensionsQuotaService uses heuristics to limit abusive requests | 5 // The QuotaService uses heuristics to limit abusive requests |
| 6 // made by extensions. In this model 'items' (e.g individual bookmarks) are | 6 // made by extensions. In this model 'items' (e.g individual bookmarks) are |
| 7 // represented by a 'Bucket' that holds state for that item for one single | 7 // represented by a 'Bucket' that holds state for that item for one single |
| 8 // interval of time. The interval of time is defined as 'how long we need to | 8 // interval of time. The interval of time is defined as 'how long we need to |
| 9 // watch an item (for a particular heuristic) before making a decision about | 9 // watch an item (for a particular heuristic) before making a decision about |
| 10 // quota violations'. A heuristic is two functions: one mapping input | 10 // quota violations'. A heuristic is two functions: one mapping input |
| 11 // arguments to a unique Bucket (the BucketMapper), and another to determine | 11 // arguments to a unique Bucket (the BucketMapper), and another to determine |
| 12 // if a new request involving such an item at a given time is a violation. | 12 // if a new request involving such an item at a given time is a violation. |
| 13 | 13 |
| 14 #ifndef CHROME_BROWSER_EXTENSIONS_EXTENSIONS_QUOTA_SERVICE_H_ | 14 #ifndef EXTENSIONS_BROWSER_QUOTA_SERVICE_H_ |
| 15 #define CHROME_BROWSER_EXTENSIONS_EXTENSIONS_QUOTA_SERVICE_H_ | 15 #define EXTENSIONS_BROWSER_QUOTA_SERVICE_H_ |
| 16 | 16 |
| 17 #include <list> | 17 #include <list> |
| 18 #include <map> | 18 #include <map> |
| 19 #include <string> | 19 #include <string> |
| 20 | 20 |
| 21 #include "base/compiler_specific.h" | 21 #include "base/compiler_specific.h" |
| 22 #include "base/containers/hash_tables.h" | 22 #include "base/containers/hash_tables.h" |
| 23 #include "base/memory/scoped_ptr.h" | 23 #include "base/memory/scoped_ptr.h" |
| 24 #include "base/threading/non_thread_safe.h" | 24 #include "base/threading/non_thread_safe.h" |
| 25 #include "base/time/time.h" | 25 #include "base/time/time.h" |
| 26 #include "base/timer/timer.h" | 26 #include "base/timer/timer.h" |
| 27 #include "base/values.h" | 27 #include "base/values.h" |
| 28 | 28 |
| 29 class ExtensionFunction; | 29 class ExtensionFunction; |
| 30 |
| 31 namespace extensions { |
| 30 class QuotaLimitHeuristic; | 32 class QuotaLimitHeuristic; |
| 33 class TestResetQuotaFunction; |
| 34 |
| 31 typedef std::list<QuotaLimitHeuristic*> QuotaLimitHeuristics; | 35 typedef std::list<QuotaLimitHeuristic*> QuotaLimitHeuristics; |
| 32 | 36 |
| 33 namespace extensions { | 37 // The QuotaService takes care that calls to certain extension |
| 34 class TestResetQuotaFunction; | |
| 35 } | |
| 36 | |
| 37 // The ExtensionsQuotaService takes care that calls to certain extension | |
| 38 // functions do not exceed predefined quotas. | 38 // functions do not exceed predefined quotas. |
| 39 // | 39 // |
| 40 // The ExtensionsQuotaService needs to live entirely on one thread, i.e. | 40 // The QuotaService needs to live entirely on one thread, i.e. |
| 41 // be created, called and destroyed on the same thread, due to its use | 41 // be created, called and destroyed on the same thread, due to its use |
| 42 // of a RepeatingTimer. | 42 // of a RepeatingTimer. |
| 43 class ExtensionsQuotaService : public base::NonThreadSafe { | 43 class QuotaService : public base::NonThreadSafe { |
| 44 public: | 44 public: |
| 45 // Some concrete heuristics (declared below) that ExtensionFunctions can | 45 // Some concrete heuristics (declared below) that ExtensionFunctions can |
| 46 // use to help the service make decisions about quota violations. | 46 // use to help the service make decisions about quota violations. |
| 47 class TimedLimit; | 47 class TimedLimit; |
| 48 class SustainedLimit; | 48 class SustainedLimit; |
| 49 | 49 |
| 50 ExtensionsQuotaService(); | 50 QuotaService(); |
| 51 virtual ~ExtensionsQuotaService(); | 51 virtual ~QuotaService(); |
| 52 | 52 |
| 53 // Decide whether the invocation of |function| with argument |args| by the | 53 // Decide whether the invocation of |function| with argument |args| by the |
| 54 // extension specified by |extension_id| results in a quota limit violation. | 54 // extension specified by |extension_id| results in a quota limit violation. |
| 55 // Returns an error message representing the failure if quota was exceeded, | 55 // Returns an error message representing the failure if quota was exceeded, |
| 56 // or empty-string if the request is fine and can proceed. | 56 // or empty-string if the request is fine and can proceed. |
| 57 std::string Assess(const std::string& extension_id, | 57 std::string Assess(const std::string& extension_id, |
| 58 ExtensionFunction* function, | 58 ExtensionFunction* function, |
| 59 const base::ListValue* args, | 59 const base::ListValue* args, |
| 60 const base::TimeTicks& event_time); | 60 const base::TimeTicks& event_time); |
| 61 | 61 |
| 62 private: | 62 private: |
| 63 friend class extensions::TestResetQuotaFunction; | 63 friend class extensions::TestResetQuotaFunction; |
| 64 typedef std::string ExtensionId; | 64 typedef std::string ExtensionId; |
| 65 typedef std::string FunctionName; | 65 typedef std::string FunctionName; |
| 66 // All QuotaLimitHeuristic instances in this map are owned by us. | 66 // All QuotaLimitHeuristic instances in this map are owned by us. |
| 67 typedef std::map<FunctionName, QuotaLimitHeuristics> FunctionHeuristicsMap; | 67 typedef std::map<FunctionName, QuotaLimitHeuristics> FunctionHeuristicsMap; |
| 68 | 68 |
| 69 // Purge resets all accumulated data (except |violation_errors_|) as if the | 69 // Purge resets all accumulated data (except |violation_errors_|) as if the |
| 70 // service was just created. Called periodically so we don't consume an | 70 // service was just created. Called periodically so we don't consume an |
| 71 // unbounded amount of memory while tracking quota. Yes, this could mean an | 71 // unbounded amount of memory while tracking quota. Yes, this could mean an |
| 72 // extension gets away with murder if it is timed right, but the extensions | 72 // extension gets away with murder if it is timed right, but the extensions |
| 73 // we are trying to limit are ones that consistently violate, so we'll | 73 // we are trying to limit are ones that consistently violate, so we'll |
| 74 // converge to the correct set. | 74 // converge to the correct set. |
| 75 void Purge(); | 75 void Purge(); |
| 76 void PurgeFunctionHeuristicsMap(FunctionHeuristicsMap* map); | 76 void PurgeFunctionHeuristicsMap(FunctionHeuristicsMap* map); |
| 77 base::RepeatingTimer<ExtensionsQuotaService> purge_timer_; | 77 base::RepeatingTimer<QuotaService> purge_timer_; |
| 78 | 78 |
| 79 // Our quota tracking state for extensions that have invoked quota limited | 79 // Our quota tracking state for extensions that have invoked quota limited |
| 80 // functions. Each extension is treated separately, so extension ids are the | 80 // functions. Each extension is treated separately, so extension ids are the |
| 81 // key for the mapping. As an extension invokes functions, the map keeps | 81 // key for the mapping. As an extension invokes functions, the map keeps |
| 82 // track of which functions it has invoked and the heuristics for each one. | 82 // track of which functions it has invoked and the heuristics for each one. |
| 83 // Each heuristic will be evaluated and ANDed together to get a final answer. | 83 // Each heuristic will be evaluated and ANDed together to get a final answer. |
| 84 std::map<ExtensionId, FunctionHeuristicsMap> function_heuristics_; | 84 std::map<ExtensionId, FunctionHeuristicsMap> function_heuristics_; |
| 85 | 85 |
| 86 // For now, as soon as an extension violates quota, we don't allow it to | 86 // For now, as soon as an extension violates quota, we don't allow it to |
| 87 // make any more requests to quota limited functions. This provides a quick | 87 // make any more requests to quota limited functions. This provides a quick |
| 88 // lookup for these extensions that is only stored in memory. | 88 // lookup for these extensions that is only stored in memory. |
| 89 typedef std::map<std::string, std::string> ViolationErrorMap; | 89 typedef std::map<std::string, std::string> ViolationErrorMap; |
| 90 ViolationErrorMap violation_errors_; | 90 ViolationErrorMap violation_errors_; |
| 91 | 91 |
| 92 DISALLOW_COPY_AND_ASSIGN(ExtensionsQuotaService); | 92 DISALLOW_COPY_AND_ASSIGN(QuotaService); |
| 93 }; | 93 }; |
| 94 | 94 |
| 95 // A QuotaLimitHeuristic is two things: 1, A heuristic to map extension | 95 // A QuotaLimitHeuristic is two things: 1, A heuristic to map extension |
| 96 // function arguments to corresponding Buckets for each input arg, and 2) a | 96 // function arguments to corresponding Buckets for each input arg, and 2) a |
| 97 // heuristic for determining if a new event involving a particular item | 97 // heuristic for determining if a new event involving a particular item |
| 98 // (represented by its Bucket) constitutes a quota violation. | 98 // (represented by its Bucket) constitutes a quota violation. |
| 99 class QuotaLimitHeuristic { | 99 class QuotaLimitHeuristic { |
| 100 public: | 100 public: |
| 101 // Parameters to configure the amount of tokens allotted to individual | 101 // Parameters to configure the amount of tokens allotted to individual |
| 102 // Bucket objects (see Below) and how often they are replenished. | 102 // Bucket objects (see Below) and how often they are replenished. |
| (...skipping 24 matching lines...) Expand all Loading... |
| 127 bool has_tokens() const { return num_tokens_ > 0; } | 127 bool has_tokens() const { return num_tokens_ > 0; } |
| 128 | 128 |
| 129 // Reset this bucket to specification (from internal configuration), to be | 129 // Reset this bucket to specification (from internal configuration), to be |
| 130 // valid from |start| until the first refill interval elapses and it needs | 130 // valid from |start| until the first refill interval elapses and it needs |
| 131 // to be reset again. | 131 // to be reset again. |
| 132 void Reset(const Config& config, const base::TimeTicks& start); | 132 void Reset(const Config& config, const base::TimeTicks& start); |
| 133 | 133 |
| 134 // The time at which the token count and next expiration should be reset, | 134 // The time at which the token count and next expiration should be reset, |
| 135 // via a call to Reset. | 135 // via a call to Reset. |
| 136 const base::TimeTicks& expiration() { return expiration_; } | 136 const base::TimeTicks& expiration() { return expiration_; } |
| 137 |
| 137 private: | 138 private: |
| 138 base::TimeTicks expiration_; | 139 base::TimeTicks expiration_; |
| 139 int64 num_tokens_; | 140 int64 num_tokens_; |
| 140 DISALLOW_COPY_AND_ASSIGN(Bucket); | 141 DISALLOW_COPY_AND_ASSIGN(Bucket); |
| 141 }; | 142 }; |
| 142 typedef std::list<Bucket*> BucketList; | 143 typedef std::list<Bucket*> BucketList; |
| 143 | 144 |
| 144 // A helper interface to retrieve the bucket corresponding to |args| from | 145 // A helper interface to retrieve the bucket corresponding to |args| from |
| 145 // the set of buckets (which is typically stored in the BucketMapper itself) | 146 // the set of buckets (which is typically stored in the BucketMapper itself) |
| 146 // for this QuotaLimitHeuristic. | 147 // for this QuotaLimitHeuristic. |
| (...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 202 scoped_ptr<BucketMapper> bucket_mapper_; | 203 scoped_ptr<BucketMapper> bucket_mapper_; |
| 203 | 204 |
| 204 // The name of the heuristic for formatting error messages. | 205 // The name of the heuristic for formatting error messages. |
| 205 std::string name_; | 206 std::string name_; |
| 206 | 207 |
| 207 DISALLOW_COPY_AND_ASSIGN(QuotaLimitHeuristic); | 208 DISALLOW_COPY_AND_ASSIGN(QuotaLimitHeuristic); |
| 208 }; | 209 }; |
| 209 | 210 |
| 210 // A simple per-item heuristic to limit the number of events that can occur in | 211 // A simple per-item heuristic to limit the number of events that can occur in |
| 211 // a given period of time; e.g "no more than 100 events in an hour". | 212 // a given period of time; e.g "no more than 100 events in an hour". |
| 212 class ExtensionsQuotaService::TimedLimit : public QuotaLimitHeuristic { | 213 class QuotaService::TimedLimit : public QuotaLimitHeuristic { |
| 213 public: | 214 public: |
| 214 TimedLimit(const Config& config, BucketMapper* map, const std::string& name) | 215 TimedLimit(const Config& config, BucketMapper* map, const std::string& name) |
| 215 : QuotaLimitHeuristic(config, map, name) {} | 216 : QuotaLimitHeuristic(config, map, name) {} |
| 216 virtual bool Apply(Bucket* bucket, | 217 virtual bool Apply(Bucket* bucket, |
| 217 const base::TimeTicks& event_time) OVERRIDE; | 218 const base::TimeTicks& event_time) OVERRIDE; |
| 218 }; | 219 }; |
| 219 | 220 |
| 220 // A per-item heuristic to limit the number of events that can occur in a | 221 // A per-item heuristic to limit the number of events that can occur in a |
| 221 // period of time over a sustained longer interval. E.g "no more than two | 222 // period of time over a sustained longer interval. E.g "no more than two |
| 222 // events per minute, sustained over 10 minutes". | 223 // events per minute, sustained over 10 minutes". |
| 223 class ExtensionsQuotaService::SustainedLimit : public QuotaLimitHeuristic { | 224 class QuotaService::SustainedLimit : public QuotaLimitHeuristic { |
| 224 public: | 225 public: |
| 225 SustainedLimit(const base::TimeDelta& sustain, | 226 SustainedLimit(const base::TimeDelta& sustain, |
| 226 const Config& config, | 227 const Config& config, |
| 227 BucketMapper* map, | 228 BucketMapper* map, |
| 228 const std::string& name); | 229 const std::string& name); |
| 229 virtual bool Apply(Bucket* bucket, | 230 virtual bool Apply(Bucket* bucket, |
| 230 const base::TimeTicks& event_time) OVERRIDE; | 231 const base::TimeTicks& event_time) OVERRIDE; |
| 232 |
| 231 private: | 233 private: |
| 232 // Specifies how long exhaustion of buckets is allowed to continue before | 234 // Specifies how long exhaustion of buckets is allowed to continue before |
| 233 // denying requests. | 235 // denying requests. |
| 234 const int64 repeat_exhaustion_allowance_; | 236 const int64 repeat_exhaustion_allowance_; |
| 235 int64 num_available_repeat_exhaustions_; | 237 int64 num_available_repeat_exhaustions_; |
| 236 }; | 238 }; |
| 237 | 239 |
| 238 #endif // CHROME_BROWSER_EXTENSIONS_EXTENSIONS_QUOTA_SERVICE_H_ | 240 } // namespace extensions |
| 241 |
| 242 #endif // EXTENSIONS_BROWSER_QUOTA_SERVICE_H_ |
| OLD | NEW |