1 // Copyright 2014 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 "extensions/browser/api/storage/storage_api.h"
10 #include "base/bind.h"
11 #include "base/strings/stringprintf.h"
12 #include "base/values.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "extensions/browser/api/storage/storage_frontend.h"
15 #include "extensions/browser/quota_service.h"
16 #include "extensions/common/api/storage.h"
18 namespace extensions {
20 using content::BrowserThread;
24 SettingsFunction::SettingsFunction()
25 : settings_namespace_(settings_namespace::INVALID),
26 tried_restoring_storage_(false) {}
28 SettingsFunction::~SettingsFunction() {}
30 bool SettingsFunction::ShouldSkipQuotaLimiting() const {
31 // Only apply quota if this is for sync storage.
32 std::string settings_namespace_string;
33 if (!args_->GetString(0, &settings_namespace_string)) {
34 // This should be EXTENSION_FUNCTION_VALIDATE(false) but there is no way
35 // to signify that from this function. It will be caught in RunImpl().
38 return settings_namespace_string != "sync";
41 bool SettingsFunction::RunImpl() {
42 std::string settings_namespace_string;
43 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &settings_namespace_string));
44 args_->Remove(0, NULL);
46 settings_namespace::FromString(settings_namespace_string);
47 EXTENSION_FUNCTION_VALIDATE(
48 settings_namespace_ != settings_namespace::INVALID);
50 StorageFrontend* frontend = StorageFrontend::Get(browser_context());
51 if (!frontend->IsStorageEnabled(settings_namespace_)) {
52 error_ = base::StringPrintf(
53 "\"%s\" is not available in this instance of Chrome",
54 settings_namespace_string.c_str());
58 observers_ = frontend->GetObservers();
59 frontend->RunWithStorage(
62 base::Bind(&SettingsFunction::AsyncRunWithStorage, this));
66 void SettingsFunction::AsyncRunWithStorage(ValueStore* storage) {
67 bool success = RunWithStorage(storage);
68 BrowserThread::PostTask(
71 base::Bind(&SettingsFunction::SendResponse, this, success));
74 bool SettingsFunction::UseReadResult(ValueStore::ReadResult result,
75 ValueStore* storage) {
76 if (result->HasError())
77 return HandleError(result->error(), storage);
79 base::DictionaryValue* dict = new base::DictionaryValue();
80 dict->Swap(&result->settings());
85 bool SettingsFunction::UseWriteResult(ValueStore::WriteResult result,
86 ValueStore* storage) {
87 if (result->HasError())
88 return HandleError(result->error(), storage);
90 if (!result->changes().empty()) {
92 &SettingsObserver::OnSettingsChanged,
95 ValueStoreChange::ToJson(result->changes()));
101 bool SettingsFunction::HandleError(const ValueStore::Error& error,
102 ValueStore* storage) {
103 // If the method failed due to corruption, and we haven't tried to fix it, we
104 // can try to restore the storage and re-run it. Otherwise, the method has
106 if (error.code == ValueStore::CORRUPTION && !tried_restoring_storage_) {
107 tried_restoring_storage_ = true;
109 // If the corruption is on a particular key, try to restore that key and
111 if (error.key.get() && storage->RestoreKey(*error.key))
112 return RunWithStorage(storage);
114 // If the full database is corrupted, try to restore the whole thing and
116 if (storage->Restore())
117 return RunWithStorage(storage);
120 error_ = error.message;
124 // Concrete settings functions
128 // Adds all StringValues from a ListValue to a vector of strings.
129 void AddAllStringValues(const base::ListValue& from,
130 std::vector<std::string>* to) {
132 std::string as_string;
133 for (base::ListValue::const_iterator it = from.begin();
134 it != from.end(); ++it) {
135 if ((*it)->GetAsString(&as_string)) {
136 to->push_back(as_string);
141 // Gets the keys of a DictionaryValue.
142 std::vector<std::string> GetKeys(const base::DictionaryValue& dict) {
143 std::vector<std::string> keys;
144 for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
145 keys.push_back(it.key());
150 // Creates quota heuristics for settings modification.
151 void GetModificationQuotaLimitHeuristics(QuotaLimitHeuristics* heuristics) {
152 QuotaLimitHeuristic::Config longLimitConfig = {
153 // See storage.json for current value.
154 core_api::storage::sync::MAX_WRITE_OPERATIONS_PER_HOUR,
155 base::TimeDelta::FromHours(1)
157 heuristics->push_back(new QuotaService::TimedLimit(
159 new QuotaLimitHeuristic::SingletonBucketMapper(),
160 "MAX_WRITE_OPERATIONS_PER_HOUR"));
162 // A max of 10 operations per minute, sustained over 10 minutes.
163 QuotaLimitHeuristic::Config shortLimitConfig = {
164 // See storage.json for current value.
165 core_api::storage::sync::MAX_SUSTAINED_WRITE_OPERATIONS_PER_MINUTE,
166 base::TimeDelta::FromMinutes(1)
168 heuristics->push_back(new QuotaService::SustainedLimit(
169 base::TimeDelta::FromMinutes(10),
171 new QuotaLimitHeuristic::SingletonBucketMapper(),
172 "MAX_SUSTAINED_WRITE_OPERATIONS_PER_MINUTE"));
177 bool StorageStorageAreaGetFunction::RunWithStorage(ValueStore* storage) {
178 base::Value* input = NULL;
179 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &input));
181 switch (input->GetType()) {
182 case base::Value::TYPE_NULL:
183 return UseReadResult(storage->Get(), storage);
185 case base::Value::TYPE_STRING: {
186 std::string as_string;
187 input->GetAsString(&as_string);
188 return UseReadResult(storage->Get(as_string), storage);
191 case base::Value::TYPE_LIST: {
192 std::vector<std::string> as_string_list;
193 AddAllStringValues(*static_cast<base::ListValue*>(input),
195 return UseReadResult(storage->Get(as_string_list), storage);
198 case base::Value::TYPE_DICTIONARY: {
199 base::DictionaryValue* as_dict =
200 static_cast<base::DictionaryValue*>(input);
201 ValueStore::ReadResult result = storage->Get(GetKeys(*as_dict));
202 if (result->HasError()) {
203 return UseReadResult(result.Pass(), storage);
206 base::DictionaryValue* with_default_values = as_dict->DeepCopy();
207 with_default_values->MergeDictionary(&result->settings());
208 return UseReadResult(
209 ValueStore::MakeReadResult(make_scoped_ptr(with_default_values)),
214 EXTENSION_FUNCTION_VALIDATE(false);
219 bool StorageStorageAreaGetBytesInUseFunction::RunWithStorage(
220 ValueStore* storage) {
221 base::Value* input = NULL;
222 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &input));
224 size_t bytes_in_use = 0;
226 switch (input->GetType()) {
227 case base::Value::TYPE_NULL:
228 bytes_in_use = storage->GetBytesInUse();
231 case base::Value::TYPE_STRING: {
232 std::string as_string;
233 input->GetAsString(&as_string);
234 bytes_in_use = storage->GetBytesInUse(as_string);
238 case base::Value::TYPE_LIST: {
239 std::vector<std::string> as_string_list;
240 AddAllStringValues(*static_cast<base::ListValue*>(input),
242 bytes_in_use = storage->GetBytesInUse(as_string_list);
247 EXTENSION_FUNCTION_VALIDATE(false);
251 SetResult(new base::FundamentalValue(static_cast<int>(bytes_in_use)));
255 bool StorageStorageAreaSetFunction::RunWithStorage(ValueStore* storage) {
256 base::DictionaryValue* input = NULL;
257 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &input));
258 return UseWriteResult(storage->Set(ValueStore::DEFAULTS, *input), storage);
261 void StorageStorageAreaSetFunction::GetQuotaLimitHeuristics(
262 QuotaLimitHeuristics* heuristics) const {
263 GetModificationQuotaLimitHeuristics(heuristics);
266 bool StorageStorageAreaRemoveFunction::RunWithStorage(ValueStore* storage) {
267 base::Value* input = NULL;
268 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &input));
270 switch (input->GetType()) {
271 case base::Value::TYPE_STRING: {
272 std::string as_string;
273 input->GetAsString(&as_string);
274 return UseWriteResult(storage->Remove(as_string), storage);
277 case base::Value::TYPE_LIST: {
278 std::vector<std::string> as_string_list;
279 AddAllStringValues(*static_cast<base::ListValue*>(input),
281 return UseWriteResult(storage->Remove(as_string_list), storage);
285 EXTENSION_FUNCTION_VALIDATE(false);
290 void StorageStorageAreaRemoveFunction::GetQuotaLimitHeuristics(
291 QuotaLimitHeuristics* heuristics) const {
292 GetModificationQuotaLimitHeuristics(heuristics);
295 bool StorageStorageAreaClearFunction::RunWithStorage(ValueStore* storage) {
296 return UseWriteResult(storage->Clear(), storage);
299 void StorageStorageAreaClearFunction::GetQuotaLimitHeuristics(
300 QuotaLimitHeuristics* heuristics) const {
301 GetModificationQuotaLimitHeuristics(heuristics);
304 } // namespace extensions