c8f3fb40b63b95df5a61cb926eb55e7b0060e7ec
[platform/framework/web/crosswalk.git] / src / extensions / browser / api / storage / storage_api.cc
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.
4
5 #include "extensions/browser/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 "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"
17
18 namespace extensions {
19
20 using content::BrowserThread;
21
22 // SettingsFunction
23
24 SettingsFunction::SettingsFunction()
25     : settings_namespace_(settings_namespace::INVALID),
26       tried_restoring_storage_(false) {}
27
28 SettingsFunction::~SettingsFunction() {}
29
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().
36     return false;
37   }
38   return settings_namespace_string != "sync";
39 }
40
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);
45   settings_namespace_ =
46       settings_namespace::FromString(settings_namespace_string);
47   EXTENSION_FUNCTION_VALIDATE(
48       settings_namespace_ != settings_namespace::INVALID);
49
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());
55     return false;
56   }
57
58   observers_ = frontend->GetObservers();
59   frontend->RunWithStorage(
60       GetExtension(),
61       settings_namespace_,
62       base::Bind(&SettingsFunction::AsyncRunWithStorage, this));
63   return true;
64 }
65
66 void SettingsFunction::AsyncRunWithStorage(ValueStore* storage) {
67   bool success = RunWithStorage(storage);
68   BrowserThread::PostTask(
69       BrowserThread::UI,
70       FROM_HERE,
71       base::Bind(&SettingsFunction::SendResponse, this, success));
72 }
73
74 bool SettingsFunction::UseReadResult(ValueStore::ReadResult result,
75                                      ValueStore* storage) {
76   if (result->HasError())
77     return HandleError(result->error(), storage);
78
79   base::DictionaryValue* dict = new base::DictionaryValue();
80   dict->Swap(&result->settings());
81   SetResult(dict);
82   return true;
83 }
84
85 bool SettingsFunction::UseWriteResult(ValueStore::WriteResult result,
86                                       ValueStore* storage) {
87   if (result->HasError())
88     return HandleError(result->error(), storage);
89
90   if (!result->changes().empty()) {
91     observers_->Notify(
92         &SettingsObserver::OnSettingsChanged,
93         extension_id(),
94         settings_namespace_,
95         ValueStoreChange::ToJson(result->changes()));
96   }
97
98   return true;
99 }
100
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
105   // failed.
106   if (error.code == ValueStore::CORRUPTION && !tried_restoring_storage_) {
107     tried_restoring_storage_ = true;
108
109     // If the corruption is on a particular key, try to restore that key and
110     // re-run.
111     if (error.key.get() && storage->RestoreKey(*error.key))
112       return RunWithStorage(storage);
113
114     // If the full database is corrupted, try to restore the whole thing and
115     // re-run.
116     if (storage->Restore())
117       return RunWithStorage(storage);
118   }
119
120   error_ = error.message;
121   return false;
122 }
123
124 // Concrete settings functions
125
126 namespace {
127
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) {
131   DCHECK(to->empty());
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);
137     }
138   }
139 }
140
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());
146   }
147   return keys;
148 }
149
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)
156   };
157   heuristics->push_back(new QuotaService::TimedLimit(
158       longLimitConfig,
159       new QuotaLimitHeuristic::SingletonBucketMapper(),
160       "MAX_WRITE_OPERATIONS_PER_HOUR"));
161
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)
167   };
168   heuristics->push_back(new QuotaService::SustainedLimit(
169       base::TimeDelta::FromMinutes(10),
170       shortLimitConfig,
171       new QuotaLimitHeuristic::SingletonBucketMapper(),
172       "MAX_SUSTAINED_WRITE_OPERATIONS_PER_MINUTE"));
173 };
174
175 }  // namespace
176
177 bool StorageStorageAreaGetFunction::RunWithStorage(ValueStore* storage) {
178   base::Value* input = NULL;
179   EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &input));
180
181   switch (input->GetType()) {
182     case base::Value::TYPE_NULL:
183       return UseReadResult(storage->Get(), storage);
184
185     case base::Value::TYPE_STRING: {
186       std::string as_string;
187       input->GetAsString(&as_string);
188       return UseReadResult(storage->Get(as_string), storage);
189     }
190
191     case base::Value::TYPE_LIST: {
192       std::vector<std::string> as_string_list;
193       AddAllStringValues(*static_cast<base::ListValue*>(input),
194                          &as_string_list);
195       return UseReadResult(storage->Get(as_string_list), storage);
196     }
197
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);
204       }
205
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)),
210           storage);
211     }
212
213     default:
214       EXTENSION_FUNCTION_VALIDATE(false);
215       return false;
216   }
217 }
218
219 bool StorageStorageAreaGetBytesInUseFunction::RunWithStorage(
220     ValueStore* storage) {
221   base::Value* input = NULL;
222   EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &input));
223
224   size_t bytes_in_use = 0;
225
226   switch (input->GetType()) {
227     case base::Value::TYPE_NULL:
228       bytes_in_use = storage->GetBytesInUse();
229       break;
230
231     case base::Value::TYPE_STRING: {
232       std::string as_string;
233       input->GetAsString(&as_string);
234       bytes_in_use = storage->GetBytesInUse(as_string);
235       break;
236     }
237
238     case base::Value::TYPE_LIST: {
239       std::vector<std::string> as_string_list;
240       AddAllStringValues(*static_cast<base::ListValue*>(input),
241                          &as_string_list);
242       bytes_in_use = storage->GetBytesInUse(as_string_list);
243       break;
244     }
245
246     default:
247       EXTENSION_FUNCTION_VALIDATE(false);
248       return false;
249   }
250
251   SetResult(new base::FundamentalValue(static_cast<int>(bytes_in_use)));
252   return true;
253 }
254
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);
259 }
260
261 void StorageStorageAreaSetFunction::GetQuotaLimitHeuristics(
262     QuotaLimitHeuristics* heuristics) const {
263   GetModificationQuotaLimitHeuristics(heuristics);
264 }
265
266 bool StorageStorageAreaRemoveFunction::RunWithStorage(ValueStore* storage) {
267   base::Value* input = NULL;
268   EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &input));
269
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);
275     }
276
277     case base::Value::TYPE_LIST: {
278       std::vector<std::string> as_string_list;
279       AddAllStringValues(*static_cast<base::ListValue*>(input),
280                          &as_string_list);
281       return UseWriteResult(storage->Remove(as_string_list), storage);
282     }
283
284     default:
285       EXTENSION_FUNCTION_VALIDATE(false);
286       return false;
287   };
288 }
289
290 void StorageStorageAreaRemoveFunction::GetQuotaLimitHeuristics(
291     QuotaLimitHeuristics* heuristics) const {
292   GetModificationQuotaLimitHeuristics(heuristics);
293 }
294
295 bool StorageStorageAreaClearFunction::RunWithStorage(ValueStore* storage) {
296   return UseWriteResult(storage->Clear(), storage);
297 }
298
299 void StorageStorageAreaClearFunction::GetQuotaLimitHeuristics(
300     QuotaLimitHeuristics* heuristics) const {
301   GetModificationQuotaLimitHeuristics(heuristics);
302 }
303
304 }  // namespace extensions