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/common/extensions/features/base_feature_provider.h" | |
6 | |
7 #include <stack> | |
8 | |
9 #include "base/json/json_reader.h" | |
10 #include "base/lazy_instance.h" | |
11 #include "base/strings/string_split.h" | |
12 #include "base/strings/string_util.h" | |
13 #include "chrome/common/extensions/features/api_feature.h" | |
14 #include "chrome/common/extensions/features/complex_feature.h" | |
15 #include "chrome/common/extensions/features/manifest_feature.h" | |
16 #include "chrome/common/extensions/features/permission_feature.h" | |
17 #include "extensions/common/extensions_client.h" | |
18 #include "grit/common_resources.h" | |
19 #include "ui/base/resource/resource_bundle.h" | |
20 | |
21 namespace extensions { | |
22 | |
23 namespace { | |
24 | |
25 template<class FeatureClass> | |
26 SimpleFeature* CreateFeature() { | |
27 SimpleFeature* feature = new FeatureClass(); | |
28 ExtensionsClient::Get()->AddExtraFeatureFilters(feature); | |
29 return feature; | |
30 } | |
31 | |
32 static BaseFeatureProvider* LoadProvider( | |
33 const std::string& name, | |
34 BaseFeatureProvider::FeatureFactory factory, | |
35 int resource_id) { | |
36 const std::string& features_file = | |
37 ResourceBundle::GetSharedInstance().GetRawDataResource( | |
38 resource_id).as_string(); | |
39 int error_code = 0; | |
40 std::string error_message; | |
41 scoped_ptr<base::Value> value(base::JSONReader::ReadAndReturnError( | |
42 features_file, base::JSON_PARSE_RFC, | |
43 &error_code, &error_message)); | |
44 DCHECK(value) << "Could not load features: " << name << " " | |
45 << error_message; | |
46 scoped_ptr<base::DictionaryValue> value_as_dict; | |
47 if (value) { | |
48 CHECK(value->IsType(base::Value::TYPE_DICTIONARY)) << name; | |
49 value_as_dict.reset(static_cast<base::DictionaryValue*>(value.release())); | |
50 } else { | |
51 // http://crbug.com/176381 | |
52 value_as_dict.reset(new base::DictionaryValue()); | |
53 } | |
54 return new BaseFeatureProvider(*value_as_dict, factory); | |
55 } | |
56 | |
57 struct Static { | |
58 Static() { | |
59 feature_providers["api"] = make_linked_ptr( | |
60 LoadProvider("api", | |
61 &CreateFeature<APIFeature>, | |
62 IDR_EXTENSION_API_FEATURES)); | |
63 feature_providers["permission"] = make_linked_ptr( | |
64 LoadProvider("permission", | |
65 &CreateFeature<PermissionFeature>, | |
66 IDR_EXTENSION_PERMISSION_FEATURES)); | |
67 feature_providers["manifest"] = make_linked_ptr( | |
68 LoadProvider("manifest", | |
69 &CreateFeature<ManifestFeature>, | |
70 IDR_EXTENSION_MANIFEST_FEATURES)); | |
71 } | |
72 | |
73 typedef std::map<std::string, linked_ptr<FeatureProvider> > | |
74 FeatureProviderMap; | |
75 | |
76 FeatureProvider* GetFeatures(const std::string& name) const { | |
77 FeatureProviderMap::const_iterator it = feature_providers.find(name); | |
78 CHECK(it != feature_providers.end()); | |
79 return it->second.get(); | |
80 } | |
81 | |
82 FeatureProviderMap feature_providers; | |
83 }; | |
84 | |
85 base::LazyInstance<Static> g_static = LAZY_INSTANCE_INITIALIZER; | |
86 | |
87 bool ParseFeature(const base::DictionaryValue* value, | |
88 const std::string& name, | |
89 SimpleFeature* feature) { | |
90 feature->set_name(name); | |
91 std::string error = feature->Parse(value); | |
92 if (!error.empty()) | |
93 LOG(ERROR) << error; | |
94 return error.empty(); | |
95 } | |
96 | |
97 } // namespace | |
98 | |
99 BaseFeatureProvider::BaseFeatureProvider(const base::DictionaryValue& root, | |
100 FeatureFactory factory) | |
101 : factory_(factory ? factory : | |
102 static_cast<FeatureFactory>(&CreateFeature<SimpleFeature>)) { | |
103 for (base::DictionaryValue::Iterator iter(root); !iter.IsAtEnd(); | |
104 iter.Advance()) { | |
105 if (iter.value().GetType() == base::Value::TYPE_DICTIONARY) { | |
106 linked_ptr<SimpleFeature> feature((*factory_)()); | |
107 | |
108 std::vector<std::string> split; | |
109 base::SplitString(iter.key(), '.', &split); | |
110 | |
111 // Push parent features on the stack, starting with the current feature. | |
112 // If one of the features has "noparent" set, stop pushing features on | |
113 // the stack. The features will then be parsed in order, starting with | |
114 // the farthest parent that is either top level or has "noparent" set. | |
115 std::stack<std::pair<std::string, const base::DictionaryValue*> > | |
116 parse_stack; | |
117 while (!split.empty()) { | |
118 std::string parent_name = JoinString(split, '.'); | |
119 split.pop_back(); | |
120 if (root.HasKey(parent_name)) { | |
121 const base::DictionaryValue* parent = NULL; | |
122 CHECK(root.GetDictionaryWithoutPathExpansion(parent_name, &parent)); | |
123 parse_stack.push(std::make_pair(parent_name, parent)); | |
124 bool no_parent = false; | |
125 parent->GetBoolean("noparent", &no_parent); | |
126 if (no_parent) | |
127 break; | |
128 } | |
129 } | |
130 | |
131 CHECK(!parse_stack.empty()); | |
132 // Parse all parent features. | |
133 bool parse_error = false; | |
134 while (!parse_stack.empty()) { | |
135 if (!ParseFeature(parse_stack.top().second, | |
136 parse_stack.top().first, | |
137 feature.get())) { | |
138 parse_error = true; | |
139 break; | |
140 } | |
141 parse_stack.pop(); | |
142 } | |
143 | |
144 if (parse_error) | |
145 continue; | |
146 | |
147 features_[iter.key()] = feature; | |
148 } else if (iter.value().GetType() == base::Value::TYPE_LIST) { | |
149 // This is a complex feature. | |
150 const base::ListValue* list = | |
151 static_cast<const base::ListValue*>(&iter.value()); | |
152 CHECK_GT(list->GetSize(), 0UL); | |
153 | |
154 scoped_ptr<ComplexFeature::FeatureList> features( | |
155 new ComplexFeature::FeatureList()); | |
156 | |
157 // Parse and add all SimpleFeatures from the list. | |
158 for (base::ListValue::const_iterator list_iter = list->begin(); | |
159 list_iter != list->end(); ++list_iter) { | |
160 if ((*list_iter)->GetType() != base::Value::TYPE_DICTIONARY) { | |
161 LOG(ERROR) << iter.key() << ": Feature rules must be dictionaries."; | |
162 continue; | |
163 } | |
164 | |
165 scoped_ptr<SimpleFeature> feature((*factory_)()); | |
166 if (!ParseFeature(static_cast<const base::DictionaryValue*>(*list_iter), | |
167 iter.key(), | |
168 feature.get())) | |
169 continue; | |
170 | |
171 features->push_back(feature.release()); | |
172 } | |
173 | |
174 linked_ptr<ComplexFeature> feature(new ComplexFeature(features.Pass())); | |
175 feature->set_name(iter.key()); | |
176 | |
177 features_[iter.key()] = feature; | |
178 } else { | |
179 LOG(ERROR) << iter.key() << ": Feature description must be dictionary or" | |
180 << " list of dictionaries."; | |
181 } | |
182 } | |
183 } | |
184 | |
185 BaseFeatureProvider::~BaseFeatureProvider() { | |
186 } | |
187 | |
188 // static | |
189 FeatureProvider* BaseFeatureProvider::GetByName( | |
190 const std::string& name) { | |
191 return g_static.Get().GetFeatures(name); | |
192 } | |
193 | |
194 const std::vector<std::string>& BaseFeatureProvider::GetAllFeatureNames() | |
195 const { | |
196 if (feature_names_.empty()) { | |
197 for (FeatureMap::const_iterator iter = features_.begin(); | |
198 iter != features_.end(); ++iter) { | |
199 feature_names_.push_back(iter->first); | |
200 } | |
201 // A std::map is sorted by its keys, so we don't need to sort feature_names_ | |
202 // now. | |
203 } | |
204 return feature_names_; | |
205 } | |
206 | |
207 Feature* BaseFeatureProvider::GetFeature(const std::string& name) const { | |
208 FeatureMap::const_iterator iter = features_.find(name); | |
209 if (iter != features_.end()) | |
210 return iter->second.get(); | |
211 else | |
212 return NULL; | |
213 } | |
214 | |
215 Feature* BaseFeatureProvider::GetParent(Feature* feature) const { | |
216 CHECK(feature); | |
217 if (feature->no_parent()) | |
218 return NULL; | |
219 | |
220 std::vector<std::string> split; | |
221 base::SplitString(feature->name(), '.', &split); | |
222 if (split.size() < 2) | |
223 return NULL; | |
224 split.pop_back(); | |
225 return GetFeature(JoinString(split, '.')); | |
226 } | |
227 | |
228 // Children of a given API are named starting with parent.name()+".", which | |
229 // means they'll be contiguous in the features_ std::map. | |
230 std::vector<Feature*> BaseFeatureProvider::GetChildren(const Feature& parent) | |
231 const { | |
232 std::string prefix = parent.name() + "."; | |
233 const FeatureMap::const_iterator first_child = features_.lower_bound(prefix); | |
234 | |
235 // All children have names before (parent.name() + ('.'+1)). | |
236 ++prefix[prefix.size() - 1]; | |
237 const FeatureMap::const_iterator after_children = | |
238 features_.lower_bound(prefix); | |
239 | |
240 std::vector<Feature*> result; | |
241 result.reserve(std::distance(first_child, after_children)); | |
242 for (FeatureMap::const_iterator it = first_child; it != after_children; | |
243 ++it) { | |
244 result.push_back(it->second.get()); | |
245 } | |
246 return result; | |
247 } | |
248 | |
249 } // namespace extensions | |
OLD | NEW |