Add ICU message format support
[chromium-blink-merge.git] / extensions / browser / api / storage / storage_api.cc
blob743eea636215c27d8128683a8d6d6aa434d13323
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"
7 #include <string>
8 #include <vector>
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;
22 // SettingsFunction
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 Run().
36 return false;
38 return settings_namespace_string != "sync";
41 ExtensionFunction::ResponseAction SettingsFunction::Run() {
42 std::string settings_namespace_string;
43 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &settings_namespace_string));
44 args_->Remove(0, NULL);
45 settings_namespace_ =
46 settings_namespace::FromString(settings_namespace_string);
47 EXTENSION_FUNCTION_VALIDATE(settings_namespace_ !=
48 settings_namespace::INVALID);
50 StorageFrontend* frontend = StorageFrontend::Get(browser_context());
51 if (!frontend->IsStorageEnabled(settings_namespace_)) {
52 return RespondNow(Error(
53 base::StringPrintf("\"%s\" is not available in this instance of Chrome",
54 settings_namespace_string.c_str())));
57 observers_ = frontend->GetObservers();
58 frontend->RunWithStorage(
59 extension(),
60 settings_namespace_,
61 base::Bind(&SettingsFunction::AsyncRunWithStorage, this));
62 return RespondLater();
65 void SettingsFunction::AsyncRunWithStorage(ValueStore* storage) {
66 ResponseValue response = RunWithStorage(storage);
67 BrowserThread::PostTask(
68 BrowserThread::UI,
69 FROM_HERE,
70 base::Bind(&SettingsFunction::Respond, this, base::Passed(&response)));
73 ExtensionFunction::ResponseValue SettingsFunction::UseReadResult(
74 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());
81 return OneArgument(dict);
84 ExtensionFunction::ResponseValue SettingsFunction::UseWriteResult(
85 ValueStore::WriteResult result,
86 ValueStore* storage) {
87 if (result->HasError())
88 return HandleError(result->error(), storage);
90 if (!result->changes().empty()) {
91 observers_->Notify(FROM_HERE, &SettingsObserver::OnSettingsChanged,
92 extension_id(), settings_namespace_,
93 ValueStoreChange::ToJson(result->changes()));
96 return NoArguments();
99 ExtensionFunction::ResponseValue SettingsFunction::HandleError(
100 const ValueStore::Error& error,
101 ValueStore* storage) {
102 // If the method failed due to corruption, and we haven't tried to fix it, we
103 // can try to restore the storage and re-run it. Otherwise, the method has
104 // failed.
105 if (error.code == ValueStore::CORRUPTION && !tried_restoring_storage_) {
106 tried_restoring_storage_ = true;
108 // If the corruption is on a particular key, try to restore that key and
109 // re-run.
110 if (error.key.get() && storage->RestoreKey(*error.key))
111 return RunWithStorage(storage);
113 // If the full database is corrupted, try to restore the whole thing and
114 // re-run.
115 if (storage->Restore())
116 return RunWithStorage(storage);
119 return Error(error.message);
122 // Concrete settings functions
124 namespace {
126 // Adds all StringValues from a ListValue to a vector of strings.
127 void AddAllStringValues(const base::ListValue& from,
128 std::vector<std::string>* to) {
129 DCHECK(to->empty());
130 std::string as_string;
131 for (base::ListValue::const_iterator it = from.begin();
132 it != from.end(); ++it) {
133 if ((*it)->GetAsString(&as_string)) {
134 to->push_back(as_string);
139 // Gets the keys of a DictionaryValue.
140 std::vector<std::string> GetKeys(const base::DictionaryValue& dict) {
141 std::vector<std::string> keys;
142 for (base::DictionaryValue::Iterator it(dict); !it.IsAtEnd(); it.Advance()) {
143 keys.push_back(it.key());
145 return keys;
148 // Creates quota heuristics for settings modification.
149 void GetModificationQuotaLimitHeuristics(QuotaLimitHeuristics* heuristics) {
150 // See storage.json for the current value of these limits.
151 QuotaLimitHeuristic::Config short_limit_config = {
152 api::storage::sync::MAX_WRITE_OPERATIONS_PER_MINUTE,
153 base::TimeDelta::FromMinutes(1)};
154 QuotaLimitHeuristic::Config long_limit_config = {
155 api::storage::sync::MAX_WRITE_OPERATIONS_PER_HOUR,
156 base::TimeDelta::FromHours(1)};
157 heuristics->push_back(new QuotaService::TimedLimit(
158 short_limit_config, new QuotaLimitHeuristic::SingletonBucketMapper(),
159 "MAX_WRITE_OPERATIONS_PER_MINUTE"));
160 heuristics->push_back(new QuotaService::TimedLimit(
161 long_limit_config, new QuotaLimitHeuristic::SingletonBucketMapper(),
162 "MAX_WRITE_OPERATIONS_PER_HOUR"));
165 } // namespace
167 ExtensionFunction::ResponseValue StorageStorageAreaGetFunction::RunWithStorage(
168 ValueStore* storage) {
169 base::Value* input = NULL;
170 if (!args_->Get(0, &input))
171 return BadMessage();
173 switch (input->GetType()) {
174 case base::Value::TYPE_NULL:
175 return UseReadResult(storage->Get(), storage);
177 case base::Value::TYPE_STRING: {
178 std::string as_string;
179 input->GetAsString(&as_string);
180 return UseReadResult(storage->Get(as_string), storage);
183 case base::Value::TYPE_LIST: {
184 std::vector<std::string> as_string_list;
185 AddAllStringValues(*static_cast<base::ListValue*>(input),
186 &as_string_list);
187 return UseReadResult(storage->Get(as_string_list), storage);
190 case base::Value::TYPE_DICTIONARY: {
191 base::DictionaryValue* as_dict =
192 static_cast<base::DictionaryValue*>(input);
193 ValueStore::ReadResult result = storage->Get(GetKeys(*as_dict));
194 if (result->HasError()) {
195 return UseReadResult(result.Pass(), storage);
198 base::DictionaryValue* with_default_values = as_dict->DeepCopy();
199 with_default_values->MergeDictionary(&result->settings());
200 return UseReadResult(
201 ValueStore::MakeReadResult(make_scoped_ptr(with_default_values)),
202 storage);
205 default:
206 return BadMessage();
210 ExtensionFunction::ResponseValue
211 StorageStorageAreaGetBytesInUseFunction::RunWithStorage(ValueStore* storage) {
212 base::Value* input = NULL;
213 if (!args_->Get(0, &input))
214 return BadMessage();
216 size_t bytes_in_use = 0;
218 switch (input->GetType()) {
219 case base::Value::TYPE_NULL:
220 bytes_in_use = storage->GetBytesInUse();
221 break;
223 case base::Value::TYPE_STRING: {
224 std::string as_string;
225 input->GetAsString(&as_string);
226 bytes_in_use = storage->GetBytesInUse(as_string);
227 break;
230 case base::Value::TYPE_LIST: {
231 std::vector<std::string> as_string_list;
232 AddAllStringValues(*static_cast<base::ListValue*>(input),
233 &as_string_list);
234 bytes_in_use = storage->GetBytesInUse(as_string_list);
235 break;
238 default:
239 return BadMessage();
242 return OneArgument(
243 new base::FundamentalValue(static_cast<int>(bytes_in_use)));
246 ExtensionFunction::ResponseValue StorageStorageAreaSetFunction::RunWithStorage(
247 ValueStore* storage) {
248 base::DictionaryValue* input = NULL;
249 if (!args_->GetDictionary(0, &input))
250 return BadMessage();
251 return UseWriteResult(storage->Set(ValueStore::DEFAULTS, *input), storage);
254 void StorageStorageAreaSetFunction::GetQuotaLimitHeuristics(
255 QuotaLimitHeuristics* heuristics) const {
256 GetModificationQuotaLimitHeuristics(heuristics);
259 ExtensionFunction::ResponseValue
260 StorageStorageAreaRemoveFunction::RunWithStorage(ValueStore* storage) {
261 base::Value* input = NULL;
262 if (!args_->Get(0, &input))
263 return BadMessage();
265 switch (input->GetType()) {
266 case base::Value::TYPE_STRING: {
267 std::string as_string;
268 input->GetAsString(&as_string);
269 return UseWriteResult(storage->Remove(as_string), storage);
272 case base::Value::TYPE_LIST: {
273 std::vector<std::string> as_string_list;
274 AddAllStringValues(*static_cast<base::ListValue*>(input),
275 &as_string_list);
276 return UseWriteResult(storage->Remove(as_string_list), storage);
279 default:
280 return BadMessage();
284 void StorageStorageAreaRemoveFunction::GetQuotaLimitHeuristics(
285 QuotaLimitHeuristics* heuristics) const {
286 GetModificationQuotaLimitHeuristics(heuristics);
289 ExtensionFunction::ResponseValue
290 StorageStorageAreaClearFunction::RunWithStorage(ValueStore* storage) {
291 return UseWriteResult(storage->Clear(), storage);
294 void StorageStorageAreaClearFunction::GetQuotaLimitHeuristics(
295 QuotaLimitHeuristics* heuristics) const {
296 GetModificationQuotaLimitHeuristics(heuristics);
299 } // namespace extensions