cc: Added inline to Tile::IsReadyToDraw
[chromium-blink-merge.git] / chromeos / network / onc / onc_merger.cc
blob57d40a18a207fb668f767bdfb567658e83ff3f61
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.
5 #include "chromeos/network/onc/onc_merger.h"
7 #include <set>
8 #include <string>
9 #include <vector>
11 #include "base/basictypes.h"
12 #include "base/logging.h"
13 #include "base/values.h"
14 #include "chromeos/network/onc/onc_constants.h"
15 #include "chromeos/network/onc/onc_signature.h"
17 namespace chromeos {
18 namespace onc {
19 namespace {
21 typedef scoped_ptr<base::DictionaryValue> DictionaryPtr;
23 // Inserts |true| at every field name in |result| that is recommended in
24 // |policy|.
25 void MarkRecommendedFieldnames(const base::DictionaryValue& policy,
26 base::DictionaryValue* result) {
27 const base::ListValue* recommended_value = NULL;
28 if (!policy.GetListWithoutPathExpansion(kRecommended, &recommended_value))
29 return;
30 for (base::ListValue::const_iterator it = recommended_value->begin();
31 it != recommended_value->end(); ++it) {
32 std::string entry;
33 if ((*it)->GetAsString(&entry))
34 result->SetBooleanWithoutPathExpansion(entry, true);
38 // Returns a dictionary which contains |true| at each path that is editable by
39 // the user. No other fields are set.
40 DictionaryPtr GetEditableFlags(const base::DictionaryValue& policy) {
41 DictionaryPtr result_editable(new base::DictionaryValue);
42 MarkRecommendedFieldnames(policy, result_editable.get());
44 // Recurse into nested dictionaries.
45 for (base::DictionaryValue::Iterator it(policy); !it.IsAtEnd();
46 it.Advance()) {
47 const base::DictionaryValue* child_policy = NULL;
48 if (it.key() == kRecommended ||
49 !it.value().GetAsDictionary(&child_policy)) {
50 continue;
53 result_editable->SetWithoutPathExpansion(
54 it.key(), GetEditableFlags(*child_policy).release());
56 return result_editable.Pass();
59 // This is the base class for merging a list of DictionaryValues in
60 // parallel. See MergeDictionaries function.
61 class MergeListOfDictionaries {
62 public:
63 typedef std::vector<const base::DictionaryValue*> DictPtrs;
65 MergeListOfDictionaries() {
68 virtual ~MergeListOfDictionaries() {
71 // For each path in any of the dictionaries |dicts|, the function
72 // MergeListOfValues is called with the list of values that are located at
73 // that path in each of the dictionaries. This function returns a new
74 // dictionary containing all results of MergeListOfValues at the respective
75 // paths. The resulting dictionary doesn't contain empty dictionaries.
76 DictionaryPtr MergeDictionaries(const DictPtrs &dicts) {
77 DictionaryPtr result(new base::DictionaryValue);
78 std::set<std::string> visited;
79 for (DictPtrs::const_iterator it_outer = dicts.begin();
80 it_outer != dicts.end(); ++it_outer) {
81 if (!*it_outer)
82 continue;
84 for (base::DictionaryValue::Iterator field(**it_outer); !field.IsAtEnd();
85 field.Advance()) {
86 const std::string& key = field.key();
87 if (key == kRecommended || !visited.insert(key).second)
88 continue;
90 scoped_ptr<base::Value> merged_value;
91 if (field.value().IsType(base::Value::TYPE_DICTIONARY)) {
92 DictPtrs nested_dicts;
93 for (DictPtrs::const_iterator it_inner = dicts.begin();
94 it_inner != dicts.end(); ++it_inner) {
95 const base::DictionaryValue* nested_dict = NULL;
96 if (*it_inner)
97 (*it_inner)->GetDictionaryWithoutPathExpansion(key, &nested_dict);
98 nested_dicts.push_back(nested_dict);
100 DictionaryPtr merged_dict(MergeNestedDictionaries(key, nested_dicts));
101 if (!merged_dict->empty())
102 merged_value = merged_dict.Pass();
103 } else {
104 std::vector<const base::Value*> values;
105 for (DictPtrs::const_iterator it_inner = dicts.begin();
106 it_inner != dicts.end(); ++it_inner) {
107 const base::Value* value = NULL;
108 if (*it_inner)
109 (*it_inner)->GetWithoutPathExpansion(key, &value);
110 values.push_back(value);
112 merged_value = MergeListOfValues(key, values);
115 if (merged_value)
116 result->SetWithoutPathExpansion(key, merged_value.release());
119 return result.Pass();
122 protected:
123 // This function is called by MergeDictionaries for each list of values that
124 // are located at the same path in each of the dictionaries. The order of the
125 // values is the same as of the given dictionaries |dicts|. If a dictionary
126 // doesn't contain a path then it's value is NULL.
127 virtual scoped_ptr<base::Value> MergeListOfValues(
128 const std::string& key,
129 const std::vector<const base::Value*>& values) = 0;
131 virtual DictionaryPtr MergeNestedDictionaries(const std::string& key,
132 const DictPtrs &dicts) {
133 return MergeDictionaries(dicts);
136 private:
137 DISALLOW_COPY_AND_ASSIGN(MergeListOfDictionaries);
140 // This is the base class for merging policies and user settings.
141 class MergeSettingsAndPolicies : public MergeListOfDictionaries {
142 public:
143 struct ValueParams {
144 const base::Value* user_policy;
145 const base::Value* device_policy;
146 const base::Value* user_setting;
147 const base::Value* shared_setting;
148 const base::Value* active_setting;
149 bool user_editable;
150 bool device_editable;
153 MergeSettingsAndPolicies() {}
155 // Merge the provided dictionaries. For each path in any of the dictionaries,
156 // MergeValues is called. Its results are collected in a new dictionary which
157 // is then returned. The resulting dictionary never contains empty
158 // dictionaries.
159 DictionaryPtr MergeDictionaries(
160 const base::DictionaryValue* user_policy,
161 const base::DictionaryValue* device_policy,
162 const base::DictionaryValue* user_settings,
163 const base::DictionaryValue* shared_settings,
164 const base::DictionaryValue* active_settings) {
165 hasUserPolicy_ = (user_policy != NULL);
166 hasDevicePolicy_ = (device_policy != NULL);
168 DictionaryPtr user_editable;
169 if (user_policy != NULL)
170 user_editable = GetEditableFlags(*user_policy);
172 DictionaryPtr device_editable;
173 if (device_policy != NULL)
174 device_editable = GetEditableFlags(*device_policy);
176 std::vector<const base::DictionaryValue*> dicts(kLastIndex, NULL);
177 dicts[kUserPolicyIndex] = user_policy;
178 dicts[kDevicePolicyIndex] = device_policy;
179 dicts[kUserSettingsIndex] = user_settings;
180 dicts[kSharedSettingsIndex] = shared_settings;
181 dicts[kActiveSettingsIndex] = active_settings;
182 dicts[kUserEditableIndex] = user_editable.get();
183 dicts[kDeviceEditableIndex] = device_editable.get();
184 return MergeListOfDictionaries::MergeDictionaries(dicts);
187 protected:
188 // This function is called by MergeDictionaries for each list of values that
189 // are located at the same path in each of the dictionaries. Implementations
190 // can use the Has*Policy functions.
191 virtual scoped_ptr<base::Value> MergeValues(const std::string& key,
192 const ValueParams& values) = 0;
194 // Whether a user policy was provided.
195 bool HasUserPolicy() {
196 return hasUserPolicy_;
199 // Whether a device policy was provided.
200 bool HasDevicePolicy() {
201 return hasDevicePolicy_;
204 // MergeListOfDictionaries override.
205 virtual scoped_ptr<base::Value> MergeListOfValues(
206 const std::string& key,
207 const std::vector<const base::Value*>& values) OVERRIDE {
208 bool user_editable = !HasUserPolicy();
209 if (values[kUserEditableIndex])
210 values[kUserEditableIndex]->GetAsBoolean(&user_editable);
212 bool device_editable = !HasDevicePolicy();
213 if (values[kDeviceEditableIndex])
214 values[kDeviceEditableIndex]->GetAsBoolean(&device_editable);
216 ValueParams params;
217 params.user_policy = values[kUserPolicyIndex];
218 params.device_policy = values[kDevicePolicyIndex];
219 params.user_setting = values[kUserSettingsIndex];
220 params.shared_setting = values[kSharedSettingsIndex];
221 params.active_setting = values[kActiveSettingsIndex];
222 params.user_editable = user_editable;
223 params.device_editable = device_editable;
224 return MergeValues(key, params);
227 private:
228 enum {
229 kUserPolicyIndex,
230 kDevicePolicyIndex,
231 kUserSettingsIndex,
232 kSharedSettingsIndex,
233 kActiveSettingsIndex,
234 kUserEditableIndex,
235 kDeviceEditableIndex,
236 kLastIndex
239 bool hasUserPolicy_, hasDevicePolicy_;
241 DISALLOW_COPY_AND_ASSIGN(MergeSettingsAndPolicies);
244 // Call MergeDictionaries to merge policies and settings to the effective
245 // values. This ignores the active settings of Shill. See the description of
246 // MergeSettingsAndPoliciesToEffective.
247 class MergeToEffective : public MergeSettingsAndPolicies {
248 public:
249 MergeToEffective() {}
251 protected:
252 // Merges |values| to the effective value (Mandatory policy overwrites user
253 // settings overwrites shared settings overwrites recommended policy). |which|
254 // is set to the respective onc::kAugmentation* constant that indicates which
255 // source of settings is effective. Note that this function may return a NULL
256 // pointer and set |which| to kAugmentationUserPolicy, which means that the
257 // user policy didn't set a value but also didn't recommend it, thus enforcing
258 // the empty value.
259 scoped_ptr<base::Value> MergeValues(const std::string& key,
260 const ValueParams& values,
261 std::string* which) {
262 const base::Value* result = NULL;
263 which->clear();
264 if (!values.user_editable) {
265 result = values.user_policy;
266 *which = kAugmentationUserPolicy;
267 } else if (!values.device_editable) {
268 result = values.device_policy;
269 *which = kAugmentationDevicePolicy;
270 } else if (values.user_setting) {
271 result = values.user_setting;
272 *which = kAugmentationUserSetting;
273 } else if (values.shared_setting) {
274 result = values.shared_setting;
275 *which = kAugmentationSharedSetting;
276 } else if (values.user_policy) {
277 result = values.user_policy;
278 *which = kAugmentationUserPolicy;
279 } else if (values.device_policy) {
280 result = values.device_policy;
281 *which = kAugmentationDevicePolicy;
282 } else {
283 // Can be reached if the current field is recommended, but none of the
284 // dictionaries contained a value for it.
286 if (result)
287 return make_scoped_ptr(result->DeepCopy());
288 return scoped_ptr<base::Value>();
291 // MergeSettingsAndPolicies override.
292 virtual scoped_ptr<base::Value> MergeValues(
293 const std::string& key,
294 const ValueParams& values) OVERRIDE {
295 std::string which;
296 return MergeValues(key, values, &which);
299 private:
300 DISALLOW_COPY_AND_ASSIGN(MergeToEffective);
303 // Call MergeDictionaries to merge policies and settings to an augmented
304 // dictionary which contains a dictionary for each value in the original
305 // dictionaries. See the description of MergeSettingsAndPoliciesToAugmented.
306 class MergeToAugmented : public MergeToEffective {
307 public:
308 MergeToAugmented() {}
310 DictionaryPtr MergeDictionaries(
311 const OncValueSignature& signature,
312 const base::DictionaryValue* user_policy,
313 const base::DictionaryValue* device_policy,
314 const base::DictionaryValue* user_settings,
315 const base::DictionaryValue* shared_settings,
316 const base::DictionaryValue* active_settings) {
317 signature_ = &signature;
318 return MergeToEffective::MergeDictionaries(user_policy,
319 device_policy,
320 user_settings,
321 shared_settings,
322 active_settings);
325 protected:
326 // MergeSettingsAndPolicies override.
327 virtual scoped_ptr<base::Value> MergeValues(
328 const std::string& key,
329 const ValueParams& values) OVERRIDE {
330 scoped_ptr<base::DictionaryValue> result(new base::DictionaryValue);
331 if (values.active_setting) {
332 result->SetWithoutPathExpansion(kAugmentationActiveSetting,
333 values.active_setting->DeepCopy());
336 const OncFieldSignature* field = NULL;
337 if (signature_)
338 field = GetFieldSignature(*signature_, key);
340 if (field) {
341 // This field is part of the provided ONCSignature, thus it can be
342 // controlled by policy.
343 std::string which_effective;
344 MergeToEffective::MergeValues(key, values, &which_effective).reset();
345 if (!which_effective.empty()) {
346 result->SetStringWithoutPathExpansion(kAugmentationEffectiveSetting,
347 which_effective);
349 bool is_credential = onc::FieldIsCredential(*signature_, key);
351 // Prevent credentials from being forwarded in cleartext to
352 // UI. User/shared credentials are not stored separately, so they cannot
353 // leak here.
354 if (!is_credential) {
355 if (values.user_policy) {
356 result->SetWithoutPathExpansion(kAugmentationUserPolicy,
357 values.user_policy->DeepCopy());
359 if (values.device_policy) {
360 result->SetWithoutPathExpansion(kAugmentationDevicePolicy,
361 values.device_policy->DeepCopy());
364 if (values.user_setting) {
365 result->SetWithoutPathExpansion(kAugmentationUserSetting,
366 values.user_setting->DeepCopy());
368 if (values.shared_setting) {
369 result->SetWithoutPathExpansion(kAugmentationSharedSetting,
370 values.shared_setting->DeepCopy());
372 if (HasUserPolicy() && values.user_editable) {
373 result->SetBooleanWithoutPathExpansion(kAugmentationUserEditable,
374 true);
376 if (HasDevicePolicy() && values.device_editable) {
377 result->SetBooleanWithoutPathExpansion(kAugmentationDeviceEditable,
378 true);
380 } else {
381 // This field is not part of the provided ONCSignature, thus it cannot be
382 // controlled by policy.
383 result->SetStringWithoutPathExpansion(kAugmentationEffectiveSetting,
384 kAugmentationUnmanaged);
386 if (result->empty())
387 result.reset();
388 return result.PassAs<base::Value>();
391 // MergeListOfDictionaries override.
392 virtual DictionaryPtr MergeNestedDictionaries(
393 const std::string& key,
394 const DictPtrs &dicts) OVERRIDE {
395 DictionaryPtr result;
396 if (signature_) {
397 const OncValueSignature* enclosing_signature = signature_;
398 signature_ = NULL;
400 const OncFieldSignature* field =
401 GetFieldSignature(*enclosing_signature, key);
402 if (field)
403 signature_ = field->value_signature;
404 result = MergeToEffective::MergeNestedDictionaries(key, dicts);
406 signature_ = enclosing_signature;
407 } else {
408 result = MergeToEffective::MergeNestedDictionaries(key, dicts);
410 return result.Pass();
413 private:
414 const OncValueSignature* signature_;
415 DISALLOW_COPY_AND_ASSIGN(MergeToAugmented);
418 } // namespace
420 DictionaryPtr MergeSettingsAndPoliciesToEffective(
421 const base::DictionaryValue* user_policy,
422 const base::DictionaryValue* device_policy,
423 const base::DictionaryValue* user_settings,
424 const base::DictionaryValue* shared_settings) {
425 MergeToEffective merger;
426 return merger.MergeDictionaries(
427 user_policy, device_policy, user_settings, shared_settings, NULL);
430 DictionaryPtr MergeSettingsAndPoliciesToAugmented(
431 const OncValueSignature& signature,
432 const base::DictionaryValue* user_policy,
433 const base::DictionaryValue* device_policy,
434 const base::DictionaryValue* user_settings,
435 const base::DictionaryValue* shared_settings,
436 const base::DictionaryValue* active_settings) {
437 MergeToAugmented merger;
438 return merger.MergeDictionaries(
439 signature, user_policy, device_policy, user_settings, shared_settings,
440 active_settings);
443 } // namespace onc
444 } // namespace chromeos