OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "chrome/browser/extensions/settings/settings_api.h" | |
6 | |
7 #include <string> | |
8 #include <vector> | |
9 | |
10 #include "base/bind.h" | |
11 #include "base/stringprintf.h" | |
12 #include "base/values.h" | |
13 #include "chrome/browser/extensions/extension_service.h" | |
14 #include "chrome/browser/extensions/extensions_quota_service.h" | |
15 #include "chrome/browser/extensions/settings/settings_frontend.h" | |
16 #include "chrome/browser/profiles/profile.h" | |
17 #include "chrome/common/extensions/api/storage.h" | |
18 #include "content/public/browser/browser_thread.h" | |
19 | |
20 namespace extensions { | |
21 | |
22 using content::BrowserThread; | |
23 | |
24 namespace { | |
25 const char kUnsupportedArgumentType[] = "Unsupported argument type"; | |
26 const char kInvalidNamespaceErrorMessage[] = | |
27 "\"%s\" is not available in this instance of Chrome"; | |
28 const char kManagedNamespaceDisabledErrorMessage[] = | |
29 "\"managed\" is disabled. Use \"--%s\" to enable it."; | |
30 const char kStorageErrorMessage[] = "Storage error"; | |
31 } // namespace | |
32 | |
33 // SettingsFunction | |
34 | |
35 SettingsFunction::SettingsFunction() | |
36 : settings_namespace_(settings_namespace::INVALID) {} | |
37 | |
38 SettingsFunction::~SettingsFunction() {} | |
39 | |
40 bool SettingsFunction::ShouldSkipQuotaLimiting() const { | |
41 // Only apply quota if this is for sync storage. | |
42 std::string settings_namespace_string; | |
43 if (!args_->GetString(0, &settings_namespace_string)) { | |
44 // This is an error but it will be caught in RunImpl(), there is no | |
45 // mechanism to signify an error from this function. | |
46 return false; | |
47 } | |
48 return settings_namespace_string != "sync"; | |
49 } | |
50 | |
51 bool SettingsFunction::RunImpl() { | |
52 std::string settings_namespace_string; | |
53 EXTENSION_FUNCTION_VALIDATE(args_->GetString(0, &settings_namespace_string)); | |
54 args_->Remove(0, NULL); | |
55 settings_namespace_ = | |
56 settings_namespace::FromString(settings_namespace_string); | |
57 EXTENSION_FUNCTION_VALIDATE( | |
58 settings_namespace_ != settings_namespace::INVALID); | |
59 | |
60 SettingsFrontend* frontend = | |
61 profile()->GetExtensionService()->settings_frontend(); | |
62 if (!frontend->IsStorageEnabled(settings_namespace_)) { | |
63 error_ = base::StringPrintf(kInvalidNamespaceErrorMessage, | |
64 settings_namespace_string.c_str()); | |
65 return false; | |
66 } | |
67 | |
68 observers_ = frontend->GetObservers(); | |
69 frontend->RunWithStorage( | |
70 extension_id(), | |
71 settings_namespace_, | |
72 base::Bind(&SettingsFunction::AsyncRunWithStorage, this)); | |
73 return true; | |
74 } | |
75 | |
76 void SettingsFunction::AsyncRunWithStorage(ValueStore* storage) { | |
77 bool success = RunWithStorage(storage); | |
78 BrowserThread::PostTask( | |
79 BrowserThread::UI, | |
80 FROM_HERE, | |
81 base::Bind(&SettingsFunction::SendResponse, this, success)); | |
82 } | |
83 | |
84 bool SettingsFunction::UseReadResult(ValueStore::ReadResult result) { | |
85 if (result->HasError()) { | |
86 error_ = result->error(); | |
87 return false; | |
88 } | |
89 | |
90 SetResult(result->settings().release()); | |
91 return true; | |
92 } | |
93 | |
94 bool SettingsFunction::UseWriteResult(ValueStore::WriteResult result) { | |
95 if (result->HasError()) { | |
96 error_ = result->error(); | |
97 return false; | |
98 } | |
99 | |
100 if (!result->changes().empty()) { | |
101 observers_->Notify( | |
102 &SettingsObserver::OnSettingsChanged, | |
103 extension_id(), | |
104 settings_namespace_, | |
105 ValueStoreChange::ToJson(result->changes())); | |
106 } | |
107 | |
108 return true; | |
109 } | |
110 | |
111 // Concrete settings functions | |
112 | |
113 namespace { | |
114 | |
115 // Adds all StringValues from a ListValue to a vector of strings. | |
116 void AddAllStringValues(const ListValue& from, std::vector<std::string>* to) { | |
117 DCHECK(to->empty()); | |
118 std::string as_string; | |
119 for (ListValue::const_iterator it = from.begin(); it != from.end(); ++it) { | |
120 if ((*it)->GetAsString(&as_string)) { | |
121 to->push_back(as_string); | |
122 } | |
123 } | |
124 } | |
125 | |
126 // Gets the keys of a DictionaryValue. | |
127 std::vector<std::string> GetKeys(const DictionaryValue& dict) { | |
128 std::vector<std::string> keys; | |
129 for (DictionaryValue::key_iterator it = dict.begin_keys(); | |
130 it != dict.end_keys(); ++it) { | |
131 keys.push_back(*it); | |
132 } | |
133 return keys; | |
134 } | |
135 | |
136 // Creates quota heuristics for settings modification. | |
137 void GetModificationQuotaLimitHeuristics(QuotaLimitHeuristics* heuristics) { | |
138 QuotaLimitHeuristic::Config longLimitConfig = { | |
139 // See storage.json for current value. | |
140 api::storage::sync::MAX_WRITE_OPERATIONS_PER_HOUR, | |
141 base::TimeDelta::FromHours(1) | |
142 }; | |
143 heuristics->push_back( | |
144 new ExtensionsQuotaService::TimedLimit( | |
145 longLimitConfig, | |
146 new QuotaLimitHeuristic::SingletonBucketMapper(), | |
147 "MAX_WRITE_OPERATIONS_PER_HOUR")); | |
148 | |
149 // A max of 10 operations per minute, sustained over 10 minutes. | |
150 QuotaLimitHeuristic::Config shortLimitConfig = { | |
151 // See storage.json for current value. | |
152 api::storage::sync::MAX_SUSTAINED_WRITE_OPERATIONS_PER_MINUTE, | |
153 base::TimeDelta::FromMinutes(1) | |
154 }; | |
155 heuristics->push_back( | |
156 new ExtensionsQuotaService::SustainedLimit( | |
157 base::TimeDelta::FromMinutes(10), | |
158 shortLimitConfig, | |
159 new QuotaLimitHeuristic::SingletonBucketMapper(), | |
160 "MAX_SUSTAINED_WRITE_OPERATIONS_PER_MINUTE")); | |
161 }; | |
162 | |
163 } // namespace | |
164 | |
165 bool GetSettingsFunction::RunWithStorage(ValueStore* storage) { | |
166 Value* input = NULL; | |
167 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &input)); | |
168 | |
169 switch (input->GetType()) { | |
170 case Value::TYPE_NULL: | |
171 return UseReadResult(storage->Get()); | |
172 | |
173 case Value::TYPE_STRING: { | |
174 std::string as_string; | |
175 input->GetAsString(&as_string); | |
176 return UseReadResult(storage->Get(as_string)); | |
177 } | |
178 | |
179 case Value::TYPE_LIST: { | |
180 std::vector<std::string> as_string_list; | |
181 AddAllStringValues(*static_cast<ListValue*>(input), &as_string_list); | |
182 return UseReadResult(storage->Get(as_string_list)); | |
183 } | |
184 | |
185 case Value::TYPE_DICTIONARY: { | |
186 DictionaryValue* as_dict = static_cast<DictionaryValue*>(input); | |
187 ValueStore::ReadResult result = storage->Get(GetKeys(*as_dict)); | |
188 if (result->HasError()) { | |
189 return UseReadResult(result.Pass()); | |
190 } | |
191 | |
192 DictionaryValue* with_default_values = as_dict->DeepCopy(); | |
193 with_default_values->MergeDictionary(result->settings().get()); | |
194 return UseReadResult( | |
195 ValueStore::MakeReadResult(with_default_values)); | |
196 } | |
197 | |
198 default: | |
199 return UseReadResult( | |
200 ValueStore::MakeReadResult(kUnsupportedArgumentType)); | |
201 } | |
202 } | |
203 | |
204 bool GetBytesInUseSettingsFunction::RunWithStorage(ValueStore* storage) { | |
205 Value* input = NULL; | |
206 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &input)); | |
207 | |
208 size_t bytes_in_use = 0; | |
209 | |
210 switch (input->GetType()) { | |
211 case Value::TYPE_NULL: | |
212 bytes_in_use = storage->GetBytesInUse(); | |
213 break; | |
214 | |
215 case Value::TYPE_STRING: { | |
216 std::string as_string; | |
217 input->GetAsString(&as_string); | |
218 bytes_in_use = storage->GetBytesInUse(as_string); | |
219 break; | |
220 } | |
221 | |
222 case Value::TYPE_LIST: { | |
223 std::vector<std::string> as_string_list; | |
224 AddAllStringValues(*static_cast<ListValue*>(input), &as_string_list); | |
225 bytes_in_use = storage->GetBytesInUse(as_string_list); | |
226 break; | |
227 } | |
228 | |
229 default: | |
230 error_ = kUnsupportedArgumentType; | |
231 return false; | |
232 } | |
233 | |
234 SetResult(Value::CreateIntegerValue(bytes_in_use)); | |
235 return true; | |
236 } | |
237 | |
238 bool SetSettingsFunction::RunWithStorage(ValueStore* storage) { | |
239 DictionaryValue* input = NULL; | |
240 EXTENSION_FUNCTION_VALIDATE(args_->GetDictionary(0, &input)); | |
241 return UseWriteResult(storage->Set(ValueStore::DEFAULTS, *input)); | |
242 } | |
243 | |
244 void SetSettingsFunction::GetQuotaLimitHeuristics( | |
245 QuotaLimitHeuristics* heuristics) const { | |
246 GetModificationQuotaLimitHeuristics(heuristics); | |
247 } | |
248 | |
249 bool RemoveSettingsFunction::RunWithStorage(ValueStore* storage) { | |
250 Value* input = NULL; | |
251 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &input)); | |
252 | |
253 switch (input->GetType()) { | |
254 case Value::TYPE_STRING: { | |
255 std::string as_string; | |
256 input->GetAsString(&as_string); | |
257 return UseWriteResult(storage->Remove(as_string)); | |
258 } | |
259 | |
260 case Value::TYPE_LIST: { | |
261 std::vector<std::string> as_string_list; | |
262 AddAllStringValues(*static_cast<ListValue*>(input), &as_string_list); | |
263 return UseWriteResult(storage->Remove(as_string_list)); | |
264 } | |
265 | |
266 default: | |
267 return UseWriteResult( | |
268 ValueStore::MakeWriteResult(kUnsupportedArgumentType)); | |
269 }; | |
270 } | |
271 | |
272 void RemoveSettingsFunction::GetQuotaLimitHeuristics( | |
273 QuotaLimitHeuristics* heuristics) const { | |
274 GetModificationQuotaLimitHeuristics(heuristics); | |
275 } | |
276 | |
277 bool ClearSettingsFunction::RunWithStorage(ValueStore* storage) { | |
278 return UseWriteResult(storage->Clear()); | |
279 } | |
280 | |
281 void ClearSettingsFunction::GetQuotaLimitHeuristics( | |
282 QuotaLimitHeuristics* heuristics) const { | |
283 GetModificationQuotaLimitHeuristics(heuristics); | |
284 } | |
285 | |
286 } // namespace extensions | |
OLD | NEW |