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.
5 #include "chrome/browser/extensions/api/storage/storage_api.h"
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"
20 namespace extensions {
22 using content::BrowserThread;
26 SettingsFunction::SettingsFunction()
27 : settings_namespace_(settings_namespace::INVALID) {}
29 SettingsFunction::~SettingsFunction() {}
31 bool SettingsFunction::ShouldSkipQuotaLimiting() const {
32 // Only apply quota if this is for sync storage.
33 std::string settings_namespace_string;
34 if (!args_->GetString(0, &settings_namespace_string)) {
35 // This should be EXTENSION_FUNCTION_VALIDATE(false) but there is no way
36 // to signify that from this function. It will be caught in RunImpl().
39 return settings_namespace_string != "sync";
42 bool SettingsFunction::RunImpl() {
43 std::string settings_namespace_string;
44 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &settings_namespace_string));
45 args_->Remove(0, NULL);
47 settings_namespace::FromString(settings_namespace_string);
48 EXTENSION_FUNCTION_VALIDATE(
49 settings_namespace_ != settings_namespace::INVALID);
51 SettingsFrontend* frontend =
52 GetProfile()->GetExtensionService()->settings_frontend();
53 if (!frontend->IsStorageEnabled(settings_namespace_)) {
54 error_ = base::StringPrintf(
55 "\"%s\" is not available in this instance of Chrome",
56 settings_namespace_string.c_str());
60 observers_ = frontend->GetObservers();
61 frontend->RunWithStorage(
64 base::Bind(&SettingsFunction::AsyncRunWithStorage, this));
68 void SettingsFunction::AsyncRunWithStorage(ValueStore* storage) {
69 bool success = RunWithStorage(storage);
70 BrowserThread::PostTask(
73 base::Bind(&SettingsFunction::SendResponse, this, success));
76 bool SettingsFunction::UseReadResult(ValueStore::ReadResult read_result) {
77 if (read_result->HasError()) {
78 error_ = read_result->error().message;
82 base::DictionaryValue* result = new base::DictionaryValue();
83 result->Swap(&read_result->settings());
88 bool SettingsFunction::UseWriteResult(ValueStore::WriteResult result) {
89 if (result->HasError()) {
90 error_ = result->error().message;
94 if (!result->changes().empty()) {
96 &SettingsObserver::OnSettingsChanged,
99 ValueStoreChange::ToJson(result->changes()));
105 // Concrete settings functions
109 // Adds all StringValues from a ListValue to a vector of strings.
110 void AddAllStringValues(const base::ListValue& from,
111 std::vector<std::string>* to) {
113 std::string as_string;
114 for (base::ListValue::const_iterator it = from.begin();
115 it != from.end(); ++it) {
116 if ((*it)->GetAsString(&as_string)) {
117 to->push_back(as_string);
122 // Gets the keys of a DictionaryValue.
123 std::vector<std::string> GetKeys(const base::DictionaryValue& dict) {
124 std::vector<std::string> keys;
125 for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
126 keys.push_back(it.key());
131 // Creates quota heuristics for settings modification.
132 void GetModificationQuotaLimitHeuristics(QuotaLimitHeuristics* heuristics) {
133 QuotaLimitHeuristic::Config longLimitConfig = {
134 // See storage.json for current value.
135 api::storage::sync::MAX_WRITE_OPERATIONS_PER_HOUR,
136 base::TimeDelta::FromHours(1)
138 heuristics->push_back(
139 new ExtensionsQuotaService::TimedLimit(
141 new QuotaLimitHeuristic::SingletonBucketMapper(),
142 "MAX_WRITE_OPERATIONS_PER_HOUR"));
144 // A max of 10 operations per minute, sustained over 10 minutes.
145 QuotaLimitHeuristic::Config shortLimitConfig = {
146 // See storage.json for current value.
147 api::storage::sync::MAX_SUSTAINED_WRITE_OPERATIONS_PER_MINUTE,
148 base::TimeDelta::FromMinutes(1)
150 heuristics->push_back(
151 new ExtensionsQuotaService::SustainedLimit(
152 base::TimeDelta::FromMinutes(10),
154 new QuotaLimitHeuristic::SingletonBucketMapper(),
155 "MAX_SUSTAINED_WRITE_OPERATIONS_PER_MINUTE"));
160 bool StorageStorageAreaGetFunction::RunWithStorage(ValueStore* storage) {
161 base::Value* input = NULL;
162 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &input));
164 switch (input->GetType()) {
165 case base::Value::TYPE_NULL:
166 return UseReadResult(storage->Get());
168 case base::Value::TYPE_STRING: {
169 std::string as_string;
170 input->GetAsString(&as_string);
171 return UseReadResult(storage->Get(as_string));
174 case base::Value::TYPE_LIST: {
175 std::vector<std::string> as_string_list;
176 AddAllStringValues(*static_cast<base::ListValue*>(input),
178 return UseReadResult(storage->Get(as_string_list));
181 case base::Value::TYPE_DICTIONARY: {
182 base::DictionaryValue* as_dict = static_cast<base::DictionaryValue*>(input);
183 ValueStore::ReadResult result = storage->Get(GetKeys(*as_dict));
184 if (result->HasError()) {
185 return UseReadResult(result.Pass());
188 base::DictionaryValue* with_default_values = as_dict->DeepCopy();
189 with_default_values->MergeDictionary(&result->settings());
190 return UseReadResult(
191 ValueStore::MakeReadResult(make_scoped_ptr(with_default_values)));
195 EXTENSION_FUNCTION_VALIDATE(false);
200 bool StorageStorageAreaGetBytesInUseFunction::RunWithStorage(
201 ValueStore* storage) {
202 base::Value* input = NULL;
203 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &input));
205 size_t bytes_in_use = 0;
207 switch (input->GetType()) {
208 case base::Value::TYPE_NULL:
209 bytes_in_use = storage->GetBytesInUse();
212 case base::Value::TYPE_STRING: {
213 std::string as_string;
214 input->GetAsString(&as_string);
215 bytes_in_use = storage->GetBytesInUse(as_string);
219 case base::Value::TYPE_LIST: {
220 std::vector<std::string> as_string_list;
221 AddAllStringValues(*static_cast<base::ListValue*>(input),
223 bytes_in_use = storage->GetBytesInUse(as_string_list);
228 EXTENSION_FUNCTION_VALIDATE(false);
232 SetResult(new base::FundamentalValue(static_cast<int>(bytes_in_use)));
236 bool StorageStorageAreaSetFunction::RunWithStorage(ValueStore* storage) {
237 base::DictionaryValue* input = NULL;
238 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &input));
239 return UseWriteResult(storage->Set(ValueStore::DEFAULTS, *input));
242 void StorageStorageAreaSetFunction::GetQuotaLimitHeuristics(
243 QuotaLimitHeuristics* heuristics) const {
244 GetModificationQuotaLimitHeuristics(heuristics);
247 bool StorageStorageAreaRemoveFunction::RunWithStorage(ValueStore* storage) {
248 base::Value* input = NULL;
249 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &input));
251 switch (input->GetType()) {
252 case base::Value::TYPE_STRING: {
253 std::string as_string;
254 input->GetAsString(&as_string);
255 return UseWriteResult(storage->Remove(as_string));
258 case base::Value::TYPE_LIST: {
259 std::vector<std::string> as_string_list;
260 AddAllStringValues(*static_cast<base::ListValue*>(input),
262 return UseWriteResult(storage->Remove(as_string_list));
266 EXTENSION_FUNCTION_VALIDATE(false);
271 void StorageStorageAreaRemoveFunction::GetQuotaLimitHeuristics(
272 QuotaLimitHeuristics* heuristics) const {
273 GetModificationQuotaLimitHeuristics(heuristics);
276 bool StorageStorageAreaClearFunction::RunWithStorage(ValueStore* storage) {
277 return UseWriteResult(storage->Clear());
280 void StorageStorageAreaClearFunction::GetQuotaLimitHeuristics(
281 QuotaLimitHeuristics* heuristics) const {
282 GetModificationQuotaLimitHeuristics(heuristics);
285 } // namespace extensions