Update To 11.40.268.0
[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 Run().
36     return false;
37   }
38   return settings_namespace_string != "sync";
39 }
40
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);
49
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())));
55   }
56
57   observers_ = frontend->GetObservers();
58   frontend->RunWithStorage(
59       extension(),
60       settings_namespace_,
61       base::Bind(&SettingsFunction::AsyncRunWithStorage, this));
62   return RespondLater();
63 }
64
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)));
71 }
72
73 ExtensionFunction::ResponseValue SettingsFunction::UseReadResult(
74     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   return OneArgument(dict);
82 }
83
84 ExtensionFunction::ResponseValue SettingsFunction::UseWriteResult(
85     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 NoArguments();
99 }
100
101 ExtensionFunction::ResponseValue SettingsFunction::HandleError(
102     const ValueStore::Error& error,
103     ValueStore* storage) {
104   // If the method failed due to corruption, and we haven't tried to fix it, we
105   // can try to restore the storage and re-run it. Otherwise, the method has
106   // failed.
107   if (error.code == ValueStore::CORRUPTION && !tried_restoring_storage_) {
108     tried_restoring_storage_ = true;
109
110     // If the corruption is on a particular key, try to restore that key and
111     // re-run.
112     if (error.key.get() && storage->RestoreKey(*error.key))
113       return RunWithStorage(storage);
114
115     // If the full database is corrupted, try to restore the whole thing and
116     // re-run.
117     if (storage->Restore())
118       return RunWithStorage(storage);
119   }
120
121   return Error(error.message);
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   // See storage.json for the current value of these limits.
153   QuotaLimitHeuristic::Config short_limit_config = {
154       core_api::storage::sync::MAX_WRITE_OPERATIONS_PER_MINUTE,
155       base::TimeDelta::FromMinutes(1)};
156   QuotaLimitHeuristic::Config long_limit_config = {
157       core_api::storage::sync::MAX_WRITE_OPERATIONS_PER_HOUR,
158       base::TimeDelta::FromHours(1)};
159   heuristics->push_back(new QuotaService::TimedLimit(
160       short_limit_config, new QuotaLimitHeuristic::SingletonBucketMapper(),
161       "MAX_WRITE_OPERATIONS_PER_MINUTE"));
162   heuristics->push_back(new QuotaService::TimedLimit(
163       long_limit_config, new QuotaLimitHeuristic::SingletonBucketMapper(),
164       "MAX_WRITE_OPERATIONS_PER_HOUR"));
165 };
166
167 }  // namespace
168
169 ExtensionFunction::ResponseValue StorageStorageAreaGetFunction::RunWithStorage(
170     ValueStore* storage) {
171   base::Value* input = NULL;
172   if (!args_->Get(0, &input))
173     return BadMessage();
174
175   switch (input->GetType()) {
176     case base::Value::TYPE_NULL:
177       return UseReadResult(storage->Get(), storage);
178
179     case base::Value::TYPE_STRING: {
180       std::string as_string;
181       input->GetAsString(&as_string);
182       return UseReadResult(storage->Get(as_string), storage);
183     }
184
185     case base::Value::TYPE_LIST: {
186       std::vector<std::string> as_string_list;
187       AddAllStringValues(*static_cast<base::ListValue*>(input),
188                          &as_string_list);
189       return UseReadResult(storage->Get(as_string_list), storage);
190     }
191
192     case base::Value::TYPE_DICTIONARY: {
193       base::DictionaryValue* as_dict =
194           static_cast<base::DictionaryValue*>(input);
195       ValueStore::ReadResult result = storage->Get(GetKeys(*as_dict));
196       if (result->HasError()) {
197         return UseReadResult(result.Pass(), storage);
198       }
199
200       base::DictionaryValue* with_default_values = as_dict->DeepCopy();
201       with_default_values->MergeDictionary(&result->settings());
202       return UseReadResult(
203           ValueStore::MakeReadResult(make_scoped_ptr(with_default_values)),
204           storage);
205     }
206
207     default:
208       return BadMessage();
209   }
210 }
211
212 ExtensionFunction::ResponseValue
213 StorageStorageAreaGetBytesInUseFunction::RunWithStorage(ValueStore* storage) {
214   base::Value* input = NULL;
215   if (!args_->Get(0, &input))
216     return BadMessage();
217
218   size_t bytes_in_use = 0;
219
220   switch (input->GetType()) {
221     case base::Value::TYPE_NULL:
222       bytes_in_use = storage->GetBytesInUse();
223       break;
224
225     case base::Value::TYPE_STRING: {
226       std::string as_string;
227       input->GetAsString(&as_string);
228       bytes_in_use = storage->GetBytesInUse(as_string);
229       break;
230     }
231
232     case base::Value::TYPE_LIST: {
233       std::vector<std::string> as_string_list;
234       AddAllStringValues(*static_cast<base::ListValue*>(input),
235                          &as_string_list);
236       bytes_in_use = storage->GetBytesInUse(as_string_list);
237       break;
238     }
239
240     default:
241       return BadMessage();
242   }
243
244   return OneArgument(
245       new base::FundamentalValue(static_cast<int>(bytes_in_use)));
246 }
247
248 ExtensionFunction::ResponseValue StorageStorageAreaSetFunction::RunWithStorage(
249     ValueStore* storage) {
250   base::DictionaryValue* input = NULL;
251   if (!args_->GetDictionary(0, &input))
252     return BadMessage();
253   return UseWriteResult(storage->Set(ValueStore::DEFAULTS, *input), storage);
254 }
255
256 void StorageStorageAreaSetFunction::GetQuotaLimitHeuristics(
257     QuotaLimitHeuristics* heuristics) const {
258   GetModificationQuotaLimitHeuristics(heuristics);
259 }
260
261 ExtensionFunction::ResponseValue
262 StorageStorageAreaRemoveFunction::RunWithStorage(ValueStore* storage) {
263   base::Value* input = NULL;
264   if (!args_->Get(0, &input))
265     return BadMessage();
266
267   switch (input->GetType()) {
268     case base::Value::TYPE_STRING: {
269       std::string as_string;
270       input->GetAsString(&as_string);
271       return UseWriteResult(storage->Remove(as_string), storage);
272     }
273
274     case base::Value::TYPE_LIST: {
275       std::vector<std::string> as_string_list;
276       AddAllStringValues(*static_cast<base::ListValue*>(input),
277                          &as_string_list);
278       return UseWriteResult(storage->Remove(as_string_list), storage);
279     }
280
281     default:
282       return BadMessage();
283   };
284 }
285
286 void StorageStorageAreaRemoveFunction::GetQuotaLimitHeuristics(
287     QuotaLimitHeuristics* heuristics) const {
288   GetModificationQuotaLimitHeuristics(heuristics);
289 }
290
291 ExtensionFunction::ResponseValue
292 StorageStorageAreaClearFunction::RunWithStorage(ValueStore* storage) {
293   return UseWriteResult(storage->Clear(), storage);
294 }
295
296 void StorageStorageAreaClearFunction::GetQuotaLimitHeuristics(
297     QuotaLimitHeuristics* heuristics) const {
298   GetModificationQuotaLimitHeuristics(heuristics);
299 }
300
301 }  // namespace extensions