Home | History | Annotate | Download | only in storage
      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
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/extensions/api/storage/storage_api.h"
      6 
      7 #include <string>
      8 #include <vector>
      9 
     10 #include "base/bind.h"
     11 #include "base/strings/stringprintf.h"
     12 #include "base/values.h"
     13 #include "chrome/browser/extensions/api/storage/settings_frontend.h"
     14 #include "chrome/browser/extensions/extension_service.h"
     15 #include "chrome/browser/extensions/extensions_quota_service.h"
     16 #include "chrome/browser/profiles/profile.h"
     17 #include "chrome/common/extensions/api/storage.h"
     18 #include "content/public/browser/browser_thread.h"
     19 
     20 namespace extensions {
     21 
     22 using content::BrowserThread;
     23 
     24 namespace {
     25 const char kUnsupportedArgumentType[] = "Unsupported argument type";
     26 const char kInvalidNamespaceErrorMessage[] =
     27     "\"%s\" is not available in this instance of Chrome";
     28 const char kManagedNamespaceDisabledErrorMessage[] =
     29     "\"managed\" is disabled. Use \"--%s\" to enable it.";
     30 const char kStorageErrorMessage[] = "Storage error";
     31 }  // namespace
     32 
     33 // SettingsFunction
     34 
     35 SettingsFunction::SettingsFunction()
     36     : settings_namespace_(settings_namespace::INVALID) {}
     37 
     38 SettingsFunction::~SettingsFunction() {}
     39 
     40 bool SettingsFunction::ShouldSkipQuotaLimiting() const {
     41   // Only apply quota if this is for sync storage.
     42   std::string settings_namespace_string;
     43   if (!args_->GetString(0, &settings_namespace_string)) {
     44     // This is an error but it will be caught in RunImpl(), there is no
     45     // mechanism to signify an error from this function.
     46     return false;
     47   }
     48   return settings_namespace_string != "sync";
     49 }
     50 
     51 bool SettingsFunction::RunImpl() {
     52   std::string settings_namespace_string;
     53   EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &settings_namespace_string));
     54   args_->Remove(0, NULL);
     55   settings_namespace_ =
     56       settings_namespace::FromString(settings_namespace_string);
     57   EXTENSION_FUNCTION_VALIDATE(
     58       settings_namespace_ != settings_namespace::INVALID);
     59 
     60   SettingsFrontend* frontend =
     61       profile()->GetExtensionService()->settings_frontend();
     62   if (!frontend->IsStorageEnabled(settings_namespace_)) {
     63     error_ = base::StringPrintf(kInvalidNamespaceErrorMessage,
     64                                 settings_namespace_string.c_str());
     65     return false;
     66   }
     67 
     68   observers_ = frontend->GetObservers();
     69   frontend->RunWithStorage(
     70       extension_id(),
     71       settings_namespace_,
     72       base::Bind(&SettingsFunction::AsyncRunWithStorage, this));
     73   return true;
     74 }
     75 
     76 void SettingsFunction::AsyncRunWithStorage(ValueStore* storage) {
     77   bool success = RunWithStorage(storage);
     78   BrowserThread::PostTask(
     79       BrowserThread::UI,
     80       FROM_HERE,
     81       base::Bind(&SettingsFunction::SendResponse, this, success));
     82 }
     83 
     84 bool SettingsFunction::UseReadResult(ValueStore::ReadResult result) {
     85   if (result->HasError()) {
     86     error_ = result->error();
     87     return false;
     88   }
     89 
     90   SetResult(result->settings().release());
     91   return true;
     92 }
     93 
     94 bool SettingsFunction::UseWriteResult(ValueStore::WriteResult result) {
     95   if (result->HasError()) {
     96     error_ = result->error();
     97     return false;
     98   }
     99 
    100   if (!result->changes().empty()) {
    101     observers_->Notify(
    102         &SettingsObserver::OnSettingsChanged,
    103         extension_id(),
    104         settings_namespace_,
    105         ValueStoreChange::ToJson(result->changes()));
    106   }
    107 
    108   return true;
    109 }
    110 
    111 // Concrete settings functions
    112 
    113 namespace {
    114 
    115 // Adds all StringValues from a ListValue to a vector of strings.
    116 void AddAllStringValues(const base::ListValue& from,
    117                         std::vector<std::string>* to) {
    118   DCHECK(to->empty());
    119   std::string as_string;
    120   for (base::ListValue::const_iterator it = from.begin();
    121        it != from.end(); ++it) {
    122     if ((*it)->GetAsString(&as_string)) {
    123       to->push_back(as_string);
    124     }
    125   }
    126 }
    127 
    128 // Gets the keys of a DictionaryValue.
    129 std::vector<std::string> GetKeys(const base::DictionaryValue& dict) {
    130   std::vector<std::string> keys;
    131   for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
    132     keys.push_back(it.key());
    133   }
    134   return keys;
    135 }
    136 
    137 // Creates quota heuristics for settings modification.
    138 void GetModificationQuotaLimitHeuristics(QuotaLimitHeuristics* heuristics) {
    139   QuotaLimitHeuristic::Config longLimitConfig = {
    140     // See storage.json for current value.
    141     api::storage::sync::MAX_WRITE_OPERATIONS_PER_HOUR,
    142     base::TimeDelta::FromHours(1)
    143   };
    144   heuristics->push_back(
    145       new ExtensionsQuotaService::TimedLimit(
    146           longLimitConfig,
    147           new QuotaLimitHeuristic::SingletonBucketMapper(),
    148           "MAX_WRITE_OPERATIONS_PER_HOUR"));
    149 
    150   // A max of 10 operations per minute, sustained over 10 minutes.
    151   QuotaLimitHeuristic::Config shortLimitConfig = {
    152     // See storage.json for current value.
    153     api::storage::sync::MAX_SUSTAINED_WRITE_OPERATIONS_PER_MINUTE,
    154     base::TimeDelta::FromMinutes(1)
    155   };
    156   heuristics->push_back(
    157       new ExtensionsQuotaService::SustainedLimit(
    158           base::TimeDelta::FromMinutes(10),
    159           shortLimitConfig,
    160           new QuotaLimitHeuristic::SingletonBucketMapper(),
    161           "MAX_SUSTAINED_WRITE_OPERATIONS_PER_MINUTE"));
    162 };
    163 
    164 }  // namespace
    165 
    166 bool StorageStorageAreaGetFunction::RunWithStorage(ValueStore* storage) {
    167   base::Value* input = NULL;
    168   EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &input));
    169 
    170   switch (input->GetType()) {
    171     case base::Value::TYPE_NULL:
    172       return UseReadResult(storage->Get());
    173 
    174     case base::Value::TYPE_STRING: {
    175       std::string as_string;
    176       input->GetAsString(&as_string);
    177       return UseReadResult(storage->Get(as_string));
    178     }
    179 
    180     case base::Value::TYPE_LIST: {
    181       std::vector<std::string> as_string_list;
    182       AddAllStringValues(*static_cast<base::ListValue*>(input),
    183                          &as_string_list);
    184       return UseReadResult(storage->Get(as_string_list));
    185     }
    186 
    187     case base::Value::TYPE_DICTIONARY: {
    188       base::DictionaryValue* as_dict = static_cast<base::DictionaryValue*>(input);
    189       ValueStore::ReadResult result = storage->Get(GetKeys(*as_dict));
    190       if (result->HasError()) {
    191         return UseReadResult(result.Pass());
    192       }
    193 
    194       base::DictionaryValue* with_default_values = as_dict->DeepCopy();
    195       with_default_values->MergeDictionary(result->settings().get());
    196       return UseReadResult(
    197           ValueStore::MakeReadResult(with_default_values));
    198     }
    199 
    200     default:
    201       return UseReadResult(
    202           ValueStore::MakeReadResult(kUnsupportedArgumentType));
    203   }
    204 }
    205 
    206 bool StorageStorageAreaGetBytesInUseFunction::RunWithStorage(
    207     ValueStore* storage) {
    208   base::Value* input = NULL;
    209   EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &input));
    210 
    211   size_t bytes_in_use = 0;
    212 
    213   switch (input->GetType()) {
    214     case base::Value::TYPE_NULL:
    215       bytes_in_use = storage->GetBytesInUse();
    216       break;
    217 
    218     case base::Value::TYPE_STRING: {
    219       std::string as_string;
    220       input->GetAsString(&as_string);
    221       bytes_in_use = storage->GetBytesInUse(as_string);
    222       break;
    223     }
    224 
    225     case base::Value::TYPE_LIST: {
    226       std::vector<std::string> as_string_list;
    227       AddAllStringValues(*static_cast<base::ListValue*>(input),
    228                          &as_string_list);
    229       bytes_in_use = storage->GetBytesInUse(as_string_list);
    230       break;
    231     }
    232 
    233     default:
    234       error_ = kUnsupportedArgumentType;
    235       return false;
    236   }
    237 
    238   SetResult(base::Value::CreateIntegerValue(bytes_in_use));
    239   return true;
    240 }
    241 
    242 bool StorageStorageAreaSetFunction::RunWithStorage(ValueStore* storage) {
    243   base::DictionaryValue* input = NULL;
    244   EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &input));
    245   return UseWriteResult(storage->Set(ValueStore::DEFAULTS, *input));
    246 }
    247 
    248 void StorageStorageAreaSetFunction::GetQuotaLimitHeuristics(
    249     QuotaLimitHeuristics* heuristics) const {
    250   GetModificationQuotaLimitHeuristics(heuristics);
    251 }
    252 
    253 bool StorageStorageAreaRemoveFunction::RunWithStorage(ValueStore* storage) {
    254   base::Value* input = NULL;
    255   EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &input));
    256 
    257   switch (input->GetType()) {
    258     case base::Value::TYPE_STRING: {
    259       std::string as_string;
    260       input->GetAsString(&as_string);
    261       return UseWriteResult(storage->Remove(as_string));
    262     }
    263 
    264     case base::Value::TYPE_LIST: {
    265       std::vector<std::string> as_string_list;
    266       AddAllStringValues(*static_cast<base::ListValue*>(input),
    267                          &as_string_list);
    268       return UseWriteResult(storage->Remove(as_string_list));
    269     }
    270 
    271     default:
    272       return UseWriteResult(
    273           ValueStore::MakeWriteResult(kUnsupportedArgumentType));
    274   };
    275 }
    276 
    277 void StorageStorageAreaRemoveFunction::GetQuotaLimitHeuristics(
    278     QuotaLimitHeuristics* heuristics) const {
    279   GetModificationQuotaLimitHeuristics(heuristics);
    280 }
    281 
    282 bool StorageStorageAreaClearFunction::RunWithStorage(ValueStore* storage) {
    283   return UseWriteResult(storage->Clear());
    284 }
    285 
    286 void StorageStorageAreaClearFunction::GetQuotaLimitHeuristics(
    287     QuotaLimitHeuristics* heuristics) const {
    288   GetModificationQuotaLimitHeuristics(heuristics);
    289 }
    290 
    291 }  // namespace extensions
    292