OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/common/extensions/api/extension_api.h" | 5 #include "chrome/common/extensions/api/extension_api.h" |
6 | 6 |
7 #include <algorithm> | 7 #include <algorithm> |
8 #include <string> | 8 #include <string> |
9 #include <vector> | 9 #include <vector> |
10 | 10 |
11 #include "base/json/json_reader.h" | 11 #include "base/json/json_reader.h" |
| 12 #include "base/json/json_writer.h" |
| 13 #include "base/lazy_instance.h" |
12 #include "base/logging.h" | 14 #include "base/logging.h" |
| 15 #include "base/string_number_conversions.h" |
13 #include "base/string_split.h" | 16 #include "base/string_split.h" |
14 #include "base/string_util.h" | 17 #include "base/string_util.h" |
15 #include "base/values.h" | 18 #include "base/values.h" |
16 #include "chrome/common/extensions/api/generated_schemas.h" | 19 #include "chrome/common/extensions/api/generated_schemas.h" |
17 #include "chrome/common/extensions/extension.h" | 20 #include "chrome/common/extensions/extension.h" |
18 #include "chrome/common/extensions/extension_permission_set.h" | 21 #include "chrome/common/extensions/extension_permission_set.h" |
| 22 #include "chrome/common/extensions/simple_feature_provider.h" |
19 #include "googleurl/src/gurl.h" | 23 #include "googleurl/src/gurl.h" |
20 #include "grit/common_resources.h" | 24 #include "grit/common_resources.h" |
21 #include "ui/base/resource/resource_bundle.h" | 25 #include "ui/base/resource/resource_bundle.h" |
22 | 26 |
23 using base::DictionaryValue; | 27 using base::DictionaryValue; |
24 using base::ListValue; | 28 using base::ListValue; |
25 using base::Value; | 29 using base::Value; |
26 | 30 |
27 namespace extensions { | 31 namespace extensions { |
28 | 32 |
29 using api::GeneratedSchemas; | 33 using api::GeneratedSchemas; |
30 | 34 |
31 namespace { | 35 namespace { |
32 | 36 |
| 37 const char* kChildKinds[] = { |
| 38 "functions", |
| 39 "events" |
| 40 }; |
| 41 |
33 // Returns whether the list at |name_space_node|.|child_kind| contains any | 42 // Returns whether the list at |name_space_node|.|child_kind| contains any |
34 // children with an { "unprivileged": true } property. | 43 // children with an { "unprivileged": true } property. |
35 bool HasUnprivilegedChild(const DictionaryValue* name_space_node, | 44 bool HasUnprivilegedChild(const DictionaryValue* name_space_node, |
36 const std::string& child_kind) { | 45 const std::string& child_kind) { |
37 ListValue* child_list = NULL; | 46 ListValue* child_list = NULL; |
38 name_space_node->GetList(child_kind, &child_list); | 47 name_space_node->GetList(child_kind, &child_list); |
39 if (!child_list) | 48 if (!child_list) |
40 return false; | 49 return false; |
41 | 50 |
42 for (size_t i = 0; i < child_list->GetSize(); ++i) { | 51 for (size_t i = 0; i < child_list->GetSize(); ++i) { |
(...skipping 17 matching lines...) Expand all Loading... |
60 base::JSONReader::ReadAndReturnError( | 69 base::JSONReader::ReadAndReturnError( |
61 schema.as_string(), | 70 schema.as_string(), |
62 false, // allow trailing commas | 71 false, // allow trailing commas |
63 NULL, // error code | 72 NULL, // error code |
64 &error_message)); | 73 &error_message)); |
65 CHECK(result.get()) << error_message; | 74 CHECK(result.get()) << error_message; |
66 CHECK(result->IsType(Value::TYPE_LIST)); | 75 CHECK(result->IsType(Value::TYPE_LIST)); |
67 return scoped_ptr<ListValue>(static_cast<ListValue*>(result.release())); | 76 return scoped_ptr<ListValue>(static_cast<ListValue*>(result.release())); |
68 } | 77 } |
69 | 78 |
| 79 DictionaryValue* FindListItem(const ListValue* list, |
| 80 const std::string& property_name, |
| 81 const std::string& property_value) { |
| 82 for (size_t i = 0; i < list->GetSize(); ++i) { |
| 83 DictionaryValue* item = NULL; |
| 84 CHECK(list->GetDictionary(i, &item)) |
| 85 << property_value << "/" << property_name; |
| 86 std::string value; |
| 87 if (item->GetString(property_name, &value) && value == property_value) |
| 88 return item; |
| 89 } |
| 90 |
| 91 return NULL; |
| 92 } |
| 93 |
| 94 const DictionaryValue* GetSchemaChild(const DictionaryValue* schema_node, |
| 95 const std::string& child_name) { |
| 96 DictionaryValue* child_node = NULL; |
| 97 for (size_t i = 0; i < arraysize(kChildKinds); ++i) { |
| 98 ListValue* list_node = NULL; |
| 99 if (!schema_node->GetList(kChildKinds[i], &list_node)) |
| 100 continue; |
| 101 child_node = FindListItem(list_node, "name", child_name); |
| 102 if (child_node) |
| 103 return child_node; |
| 104 } |
| 105 |
| 106 return NULL; |
| 107 } |
| 108 |
| 109 struct Static { |
| 110 Static() { |
| 111 api.InitDefaultConfiguration(); |
| 112 } |
| 113 ExtensionAPI api; |
| 114 }; |
| 115 |
| 116 base::LazyInstance<Static> g_lazy_instance = LAZY_INSTANCE_INITIALIZER; |
| 117 |
70 } // namespace | 118 } // namespace |
71 | 119 |
72 // static | 120 // static |
73 ExtensionAPI* ExtensionAPI::GetInstance() { | 121 ExtensionAPI* ExtensionAPI::GetSharedInstance() { |
74 return Singleton<ExtensionAPI>::get(); | 122 return &g_lazy_instance.Get().api; |
| 123 } |
| 124 |
| 125 // static |
| 126 ExtensionAPI* ExtensionAPI::CreateWithDefaultConfiguration() { |
| 127 ExtensionAPI* api = new ExtensionAPI(); |
| 128 api->InitDefaultConfiguration(); |
| 129 return api; |
| 130 } |
| 131 |
| 132 // static |
| 133 void ExtensionAPI::SplitDependencyName(const std::string& full_name, |
| 134 std::string* feature_type, |
| 135 std::string* feature_name) { |
| 136 size_t colon_index = full_name.find(':'); |
| 137 if (colon_index == std::string::npos) { |
| 138 // TODO(aa): Remove this code when all API descriptions have been updated. |
| 139 *feature_type = "api"; |
| 140 *feature_name = full_name; |
| 141 return; |
| 142 } |
| 143 |
| 144 *feature_type = full_name.substr(0, colon_index); |
| 145 *feature_name = full_name.substr(colon_index + 1); |
75 } | 146 } |
76 | 147 |
77 void ExtensionAPI::LoadSchema(const base::StringPiece& schema) { | 148 void ExtensionAPI::LoadSchema(const base::StringPiece& schema) { |
78 scoped_ptr<ListValue> schema_list(LoadSchemaList(schema)); | 149 scoped_ptr<ListValue> schema_list(LoadSchemaList(schema)); |
79 std::string schema_namespace; | 150 std::string schema_namespace; |
80 | 151 |
81 while (!schema_list->empty()) { | 152 while (!schema_list->empty()) { |
82 const DictionaryValue* schema = NULL; | 153 const DictionaryValue* schema = NULL; |
83 { | 154 { |
84 Value* value = NULL; | 155 Value* value = NULL; |
(...skipping 23 matching lines...) Expand all Loading... |
108 if (schema->GetList("matches", &matches)) { | 179 if (schema->GetList("matches", &matches)) { |
109 URLPatternSet pattern_set; | 180 URLPatternSet pattern_set; |
110 for (size_t i = 0; i < matches->GetSize(); ++i) { | 181 for (size_t i = 0; i < matches->GetSize(); ++i) { |
111 std::string pattern; | 182 std::string pattern; |
112 CHECK(matches->GetString(i, &pattern)); | 183 CHECK(matches->GetString(i, &pattern)); |
113 pattern_set.AddPattern( | 184 pattern_set.AddPattern( |
114 URLPattern(UserScript::kValidUserScriptSchemes, pattern)); | 185 URLPattern(UserScript::kValidUserScriptSchemes, pattern)); |
115 } | 186 } |
116 url_matching_apis_[schema_namespace] = pattern_set; | 187 url_matching_apis_[schema_namespace] = pattern_set; |
117 } | 188 } |
| 189 |
| 190 // Populate feature maps. |
| 191 // TODO(aa): Consider not storing features that can never run on the current |
| 192 // machine (e.g., because of platform restrictions). |
| 193 bool uses_feature_system = false; |
| 194 schema->GetBoolean("uses_feature_system", &uses_feature_system); |
| 195 if (!uses_feature_system) |
| 196 continue; |
| 197 |
| 198 Feature* feature = new Feature(); |
| 199 feature->set_name(schema_namespace); |
| 200 feature->Parse(schema); |
| 201 |
| 202 FeatureMap* schema_features = new FeatureMap(); |
| 203 CHECK(features_.insert( |
| 204 std::make_pair(schema_namespace, |
| 205 make_linked_ptr(schema_features))).second); |
| 206 CHECK(schema_features->insert( |
| 207 std::make_pair("", make_linked_ptr(feature))).second); |
| 208 |
| 209 for (size_t i = 0; i < arraysize(kChildKinds); ++i) { |
| 210 ListValue* child_list = NULL; |
| 211 schema->GetList(kChildKinds[i], &child_list); |
| 212 if (!child_list) |
| 213 continue; |
| 214 |
| 215 for (size_t j = 0; j < child_list->GetSize(); ++j) { |
| 216 DictionaryValue* child = NULL; |
| 217 CHECK(child_list->GetDictionary(j, &child)); |
| 218 |
| 219 scoped_ptr<Feature> child_feature(new Feature(*feature)); |
| 220 child_feature->Parse(child); |
| 221 if (child_feature->Equals(*feature)) |
| 222 continue; // no need to store no-op features |
| 223 |
| 224 std::string child_name; |
| 225 CHECK(child->GetString("name", &child_name)); |
| 226 child_feature->set_name(schema_namespace + "." + child_name); |
| 227 CHECK(schema_features->insert( |
| 228 std::make_pair(child_name, |
| 229 make_linked_ptr(child_feature.release()))).second); |
| 230 } |
| 231 } |
118 } | 232 } |
119 } | 233 } |
120 | 234 |
121 ExtensionAPI::ExtensionAPI() { | 235 ExtensionAPI::ExtensionAPI() { |
| 236 RegisterDependencyProvider("api", this); |
| 237 |
| 238 // TODO(aa): Can remove this when all JSON files are converted. |
| 239 RegisterDependencyProvider("", this); |
| 240 } |
| 241 |
| 242 ExtensionAPI::~ExtensionAPI() { |
| 243 } |
| 244 |
| 245 void ExtensionAPI::InitDefaultConfiguration() { |
| 246 RegisterDependencyProvider( |
| 247 "manifest", SimpleFeatureProvider::GetManifestFeatures()); |
| 248 RegisterDependencyProvider( |
| 249 "permission", SimpleFeatureProvider::GetPermissionFeatures()); |
| 250 |
122 // Schemas to be loaded from resources. | 251 // Schemas to be loaded from resources. |
123 unloaded_schemas_["app"] = ReadFromResource( | 252 CHECK(unloaded_schemas_.empty()); |
124 IDR_EXTENSION_API_JSON_APP); | 253 RegisterSchema("app", ReadFromResource( |
125 unloaded_schemas_["bookmarks"] = ReadFromResource( | 254 IDR_EXTENSION_API_JSON_APP)); |
126 IDR_EXTENSION_API_JSON_BOOKMARKS); | 255 RegisterSchema("bookmarks", ReadFromResource( |
127 unloaded_schemas_["browserAction"] = ReadFromResource( | 256 IDR_EXTENSION_API_JSON_BOOKMARKS)); |
128 IDR_EXTENSION_API_JSON_BROWSERACTION); | 257 RegisterSchema("browserAction", ReadFromResource( |
129 unloaded_schemas_["browsingData"] = ReadFromResource( | 258 IDR_EXTENSION_API_JSON_BROWSERACTION)); |
130 IDR_EXTENSION_API_JSON_BROWSINGDATA); | 259 RegisterSchema("browsingData", ReadFromResource( |
131 unloaded_schemas_["chromeAuthPrivate"] = ReadFromResource( | 260 IDR_EXTENSION_API_JSON_BROWSINGDATA)); |
132 IDR_EXTENSION_API_JSON_CHROMEAUTHPRIVATE); | 261 RegisterSchema("chromeAuthPrivate", ReadFromResource( |
133 unloaded_schemas_["chromeosInfoPrivate"] = ReadFromResource( | 262 IDR_EXTENSION_API_JSON_CHROMEAUTHPRIVATE)); |
134 IDR_EXTENSION_API_JSON_CHROMEOSINFOPRIVATE); | 263 RegisterSchema("chromeosInfoPrivate", ReadFromResource( |
135 unloaded_schemas_["contentSettings"] = ReadFromResource( | 264 IDR_EXTENSION_API_JSON_CHROMEOSINFOPRIVATE)); |
136 IDR_EXTENSION_API_JSON_CONTENTSETTINGS); | 265 RegisterSchema("contentSettings", ReadFromResource( |
137 unloaded_schemas_["contextMenus"] = ReadFromResource( | 266 IDR_EXTENSION_API_JSON_CONTENTSETTINGS)); |
138 IDR_EXTENSION_API_JSON_CONTEXTMENUS); | 267 RegisterSchema("contextMenus", ReadFromResource( |
139 unloaded_schemas_["cookies"] = ReadFromResource( | 268 IDR_EXTENSION_API_JSON_CONTEXTMENUS)); |
140 IDR_EXTENSION_API_JSON_COOKIES); | 269 RegisterSchema("cookies", ReadFromResource( |
141 unloaded_schemas_["debugger"] = ReadFromResource( | 270 IDR_EXTENSION_API_JSON_COOKIES)); |
142 IDR_EXTENSION_API_JSON_DEBUGGER); | 271 RegisterSchema("debugger", ReadFromResource( |
143 unloaded_schemas_["devtools"] = ReadFromResource( | 272 IDR_EXTENSION_API_JSON_DEBUGGER)); |
144 IDR_EXTENSION_API_JSON_DEVTOOLS); | 273 RegisterSchema("devtools", ReadFromResource( |
145 unloaded_schemas_["experimental.accessibility"] = ReadFromResource( | 274 IDR_EXTENSION_API_JSON_DEVTOOLS)); |
146 IDR_EXTENSION_API_JSON_EXPERIMENTAL_ACCESSIBILITY); | 275 RegisterSchema("experimental.accessibility", ReadFromResource( |
147 unloaded_schemas_["experimental.alarms"] = ReadFromResource( | 276 IDR_EXTENSION_API_JSON_EXPERIMENTAL_ACCESSIBILITY)); |
148 IDR_EXTENSION_API_JSON_EXPERIMENTAL_ALARMS); | 277 RegisterSchema("experimental.alarms", ReadFromResource( |
149 unloaded_schemas_["experimental.app"] = ReadFromResource( | 278 IDR_EXTENSION_API_JSON_EXPERIMENTAL_ALARMS)); |
150 IDR_EXTENSION_API_JSON_EXPERIMENTAL_APP); | 279 RegisterSchema("experimental.app", ReadFromResource( |
151 unloaded_schemas_["experimental.bookmarkManager"] = ReadFromResource( | 280 IDR_EXTENSION_API_JSON_EXPERIMENTAL_APP)); |
152 IDR_EXTENSION_API_JSON_EXPERIMENTAL_BOOKMARKMANAGER); | 281 RegisterSchema("experimental.bookmarkManager", ReadFromResource( |
153 unloaded_schemas_["experimental.declarative"] = ReadFromResource( | 282 IDR_EXTENSION_API_JSON_EXPERIMENTAL_BOOKMARKMANAGER)); |
154 IDR_EXTENSION_API_JSON_EXPERIMENTAL_DECLARATIVE); | 283 RegisterSchema("experimental.declarative", ReadFromResource( |
155 unloaded_schemas_["experimental.downloads"] = ReadFromResource( | 284 IDR_EXTENSION_API_JSON_EXPERIMENTAL_DECLARATIVE)); |
156 IDR_EXTENSION_API_JSON_EXPERIMENTAL_DOWNLOADS); | 285 RegisterSchema("experimental.downloads", ReadFromResource( |
157 unloaded_schemas_["experimental.extension"] = ReadFromResource( | 286 IDR_EXTENSION_API_JSON_EXPERIMENTAL_DOWNLOADS)); |
158 IDR_EXTENSION_API_JSON_EXPERIMENTAL_EXTENSION); | 287 RegisterSchema("experimental.extension", ReadFromResource( |
159 unloaded_schemas_["experimental.fontSettings"] = ReadFromResource( | 288 IDR_EXTENSION_API_JSON_EXPERIMENTAL_EXTENSION)); |
160 IDR_EXTENSION_API_JSON_EXPERIMENTAL_FONTSSETTINGS); | 289 RegisterSchema("experimental.fontSettings", ReadFromResource( |
161 unloaded_schemas_["experimental.identity"] = ReadFromResource( | 290 IDR_EXTENSION_API_JSON_EXPERIMENTAL_FONTSSETTINGS)); |
162 IDR_EXTENSION_API_JSON_EXPERIMENTAL_IDENTITY); | 291 RegisterSchema("experimental.identity", ReadFromResource( |
163 unloaded_schemas_["experimental.infobars"] = ReadFromResource( | 292 IDR_EXTENSION_API_JSON_EXPERIMENTAL_IDENTITY)); |
164 IDR_EXTENSION_API_JSON_EXPERIMENTAL_INFOBARS); | 293 RegisterSchema("experimental.infobars", ReadFromResource( |
165 unloaded_schemas_["experimental.input.ui"] = ReadFromResource( | 294 IDR_EXTENSION_API_JSON_EXPERIMENTAL_INFOBARS)); |
166 IDR_EXTENSION_API_JSON_EXPERIMENTAL_INPUT_UI); | 295 RegisterSchema("experimental.input.ui", ReadFromResource( |
167 unloaded_schemas_["experimental.input.virtualKeyboard"] = ReadFromResource( | 296 IDR_EXTENSION_API_JSON_EXPERIMENTAL_INPUT_UI)); |
168 IDR_EXTENSION_API_JSON_EXPERIMENTAL_INPUT_VIRTUALKEYBOARD); | 297 RegisterSchema("experimental.input.virtualKeyboard", ReadFromResource( |
169 unloaded_schemas_["experimental.keybinding"] = ReadFromResource( | 298 IDR_EXTENSION_API_JSON_EXPERIMENTAL_INPUT_VIRTUALKEYBOARD)); |
170 IDR_EXTENSION_API_JSON_EXPERIMENTAL_KEYBINDING); | 299 RegisterSchema("experimental.keybinding", ReadFromResource( |
171 unloaded_schemas_["experimental.managedMode"] = ReadFromResource( | 300 IDR_EXTENSION_API_JSON_EXPERIMENTAL_KEYBINDING)); |
172 IDR_EXTENSION_API_JSON_EXPERIMENTAL_MANAGEDMODE); | 301 RegisterSchema("experimental.managedMode", ReadFromResource( |
173 unloaded_schemas_["experimental.offscreenTabs"] = ReadFromResource( | 302 IDR_EXTENSION_API_JSON_EXPERIMENTAL_MANAGEDMODE)); |
174 IDR_EXTENSION_API_JSON_EXPERIMENTAL_OFFSCREENTABS); | 303 RegisterSchema("experimental.offscreenTabs", ReadFromResource( |
175 unloaded_schemas_["experimental.processes"] = ReadFromResource( | 304 IDR_EXTENSION_API_JSON_EXPERIMENTAL_OFFSCREENTABS)); |
176 IDR_EXTENSION_API_JSON_EXPERIMENTAL_PROCESSES); | 305 RegisterSchema("experimental.processes", ReadFromResource( |
177 unloaded_schemas_["experimental.rlz"] = ReadFromResource( | 306 IDR_EXTENSION_API_JSON_EXPERIMENTAL_PROCESSES)); |
178 IDR_EXTENSION_API_JSON_EXPERIMENTAL_RLZ); | 307 RegisterSchema("experimental.rlz", ReadFromResource( |
179 unloaded_schemas_["experimental.serial"] = ReadFromResource( | 308 IDR_EXTENSION_API_JSON_EXPERIMENTAL_RLZ)); |
180 IDR_EXTENSION_API_JSON_EXPERIMENTAL_SERIAL); | 309 RegisterSchema("experimental.serial", ReadFromResource( |
181 unloaded_schemas_["experimental.socket"] = ReadFromResource( | 310 IDR_EXTENSION_API_JSON_EXPERIMENTAL_SERIAL)); |
182 IDR_EXTENSION_API_JSON_EXPERIMENTAL_SOCKET); | 311 RegisterSchema("experimental.socket", ReadFromResource( |
183 unloaded_schemas_["experimental.speechInput"] = ReadFromResource( | 312 IDR_EXTENSION_API_JSON_EXPERIMENTAL_SOCKET)); |
184 IDR_EXTENSION_API_JSON_EXPERIMENTAL_SPEECHINPUT); | 313 RegisterSchema("experimental.speechInput", ReadFromResource( |
185 unloaded_schemas_["experimental.webRequest"] = ReadFromResource( | 314 IDR_EXTENSION_API_JSON_EXPERIMENTAL_SPEECHINPUT)); |
186 IDR_EXTENSION_API_JSON_EXPERIMENTAL_WEBREQUEST); | 315 RegisterSchema("experimental.webRequest", ReadFromResource( |
187 unloaded_schemas_["extension"] = ReadFromResource( | 316 IDR_EXTENSION_API_JSON_EXPERIMENTAL_WEBREQUEST)); |
188 IDR_EXTENSION_API_JSON_EXTENSION); | 317 RegisterSchema("extension", ReadFromResource( |
189 unloaded_schemas_["fileBrowserHandler"] = ReadFromResource( | 318 IDR_EXTENSION_API_JSON_EXTENSION)); |
190 IDR_EXTENSION_API_JSON_FILEBROWSERHANDLER); | 319 RegisterSchema("fileBrowserHandler", ReadFromResource( |
191 unloaded_schemas_["fileBrowserPrivate"] = ReadFromResource( | 320 IDR_EXTENSION_API_JSON_FILEBROWSERHANDLER)); |
192 IDR_EXTENSION_API_JSON_FILEBROWSERPRIVATE); | 321 RegisterSchema("fileBrowserPrivate", ReadFromResource( |
193 unloaded_schemas_["history"] = ReadFromResource( | 322 IDR_EXTENSION_API_JSON_FILEBROWSERPRIVATE)); |
194 IDR_EXTENSION_API_JSON_HISTORY); | 323 RegisterSchema("history", ReadFromResource( |
195 unloaded_schemas_["i18n"] = ReadFromResource( | 324 IDR_EXTENSION_API_JSON_HISTORY)); |
196 IDR_EXTENSION_API_JSON_I18N); | 325 RegisterSchema("i18n", ReadFromResource( |
197 unloaded_schemas_["idle"] = ReadFromResource( | 326 IDR_EXTENSION_API_JSON_I18N)); |
198 IDR_EXTENSION_API_JSON_IDLE); | 327 RegisterSchema("idle", ReadFromResource( |
199 unloaded_schemas_["input.ime"] = ReadFromResource( | 328 IDR_EXTENSION_API_JSON_IDLE)); |
200 IDR_EXTENSION_API_JSON_INPUT_IME); | 329 RegisterSchema("input.ime", ReadFromResource( |
201 unloaded_schemas_["inputMethodPrivate"] = ReadFromResource( | 330 IDR_EXTENSION_API_JSON_INPUT_IME)); |
202 IDR_EXTENSION_API_JSON_INPUTMETHODPRIVATE); | 331 RegisterSchema("inputMethodPrivate", ReadFromResource( |
203 unloaded_schemas_["management"] = ReadFromResource( | 332 IDR_EXTENSION_API_JSON_INPUTMETHODPRIVATE)); |
204 IDR_EXTENSION_API_JSON_MANAGEMENT); | 333 RegisterSchema("management", ReadFromResource( |
205 unloaded_schemas_["mediaPlayerPrivate"] = ReadFromResource( | 334 IDR_EXTENSION_API_JSON_MANAGEMENT)); |
206 IDR_EXTENSION_API_JSON_MEDIAPLAYERPRIVATE); | 335 RegisterSchema("mediaPlayerPrivate", ReadFromResource( |
207 unloaded_schemas_["metricsPrivate"] = ReadFromResource( | 336 IDR_EXTENSION_API_JSON_MEDIAPLAYERPRIVATE)); |
208 IDR_EXTENSION_API_JSON_METRICSPRIVATE); | 337 RegisterSchema("metricsPrivate", ReadFromResource( |
209 unloaded_schemas_["offersPrivate"] = ReadFromResource( | 338 IDR_EXTENSION_API_JSON_METRICSPRIVATE)); |
210 IDR_EXTENSION_API_JSON_OFFERSPRIVATE); | 339 RegisterSchema("offersPrivate", ReadFromResource( |
211 unloaded_schemas_["omnibox"] = ReadFromResource( | 340 IDR_EXTENSION_API_JSON_OFFERSPRIVATE)); |
212 IDR_EXTENSION_API_JSON_OMNIBOX); | 341 RegisterSchema("omnibox", ReadFromResource( |
213 unloaded_schemas_["pageAction"] = ReadFromResource( | 342 IDR_EXTENSION_API_JSON_OMNIBOX)); |
214 IDR_EXTENSION_API_JSON_PAGEACTION); | 343 RegisterSchema("pageAction", ReadFromResource( |
215 unloaded_schemas_["pageActions"] = ReadFromResource( | 344 IDR_EXTENSION_API_JSON_PAGEACTION)); |
216 IDR_EXTENSION_API_JSON_PAGEACTIONS); | 345 RegisterSchema("pageActions", ReadFromResource( |
217 unloaded_schemas_["pageCapture"] = ReadFromResource( | 346 IDR_EXTENSION_API_JSON_PAGEACTIONS)); |
218 IDR_EXTENSION_API_JSON_PAGECAPTURE); | 347 RegisterSchema("pageCapture", ReadFromResource( |
219 unloaded_schemas_["permissions"] = ReadFromResource( | 348 IDR_EXTENSION_API_JSON_PAGECAPTURE)); |
220 IDR_EXTENSION_API_JSON_PERMISSIONS); | 349 RegisterSchema("permissions", ReadFromResource( |
221 unloaded_schemas_["privacy"] = ReadFromResource( | 350 IDR_EXTENSION_API_JSON_PERMISSIONS)); |
222 IDR_EXTENSION_API_JSON_PRIVACY); | 351 RegisterSchema("privacy", ReadFromResource( |
223 unloaded_schemas_["proxy"] = ReadFromResource( | 352 IDR_EXTENSION_API_JSON_PRIVACY)); |
224 IDR_EXTENSION_API_JSON_PROXY); | 353 RegisterSchema("proxy", ReadFromResource( |
225 unloaded_schemas_["storage"] = ReadFromResource( | 354 IDR_EXTENSION_API_JSON_PROXY)); |
226 IDR_EXTENSION_API_JSON_STORAGE); | 355 RegisterSchema("storage", ReadFromResource( |
227 unloaded_schemas_["systemPrivate"] = ReadFromResource( | 356 IDR_EXTENSION_API_JSON_STORAGE)); |
228 IDR_EXTENSION_API_JSON_SYSTEMPRIVATE); | 357 RegisterSchema("systemPrivate", ReadFromResource( |
229 unloaded_schemas_["tabs"] = ReadFromResource( | 358 IDR_EXTENSION_API_JSON_SYSTEMPRIVATE)); |
230 IDR_EXTENSION_API_JSON_TABS); | 359 RegisterSchema("tabs", ReadFromResource( |
231 unloaded_schemas_["terminalPrivate"] = ReadFromResource( | 360 IDR_EXTENSION_API_JSON_TABS)); |
232 IDR_EXTENSION_API_JSON_TERMINALPRIVATE); | 361 RegisterSchema("terminalPrivate", ReadFromResource( |
233 unloaded_schemas_["test"] = ReadFromResource( | 362 IDR_EXTENSION_API_JSON_TERMINALPRIVATE)); |
234 IDR_EXTENSION_API_JSON_TEST); | 363 RegisterSchema("test", ReadFromResource( |
235 unloaded_schemas_["topSites"] = ReadFromResource( | 364 IDR_EXTENSION_API_JSON_TEST)); |
236 IDR_EXTENSION_API_JSON_TOPSITES); | 365 RegisterSchema("topSites", ReadFromResource( |
237 unloaded_schemas_["ttsEngine"] = ReadFromResource( | 366 IDR_EXTENSION_API_JSON_TOPSITES)); |
238 IDR_EXTENSION_API_JSON_TTSENGINE); | 367 RegisterSchema("ttsEngine", ReadFromResource( |
239 unloaded_schemas_["tts"] = ReadFromResource( | 368 IDR_EXTENSION_API_JSON_TTSENGINE)); |
240 IDR_EXTENSION_API_JSON_TTS); | 369 RegisterSchema("tts", ReadFromResource( |
241 unloaded_schemas_["types"] = ReadFromResource( | 370 IDR_EXTENSION_API_JSON_TTS)); |
242 IDR_EXTENSION_API_JSON_TYPES); | 371 RegisterSchema("types", ReadFromResource( |
243 unloaded_schemas_["webNavigation"] = ReadFromResource( | 372 IDR_EXTENSION_API_JSON_TYPES)); |
244 IDR_EXTENSION_API_JSON_WEBNAVIGATION); | 373 RegisterSchema("webNavigation", ReadFromResource( |
245 unloaded_schemas_["webRequest"] = ReadFromResource( | 374 IDR_EXTENSION_API_JSON_WEBNAVIGATION)); |
246 IDR_EXTENSION_API_JSON_WEBREQUEST); | 375 RegisterSchema("webRequest", ReadFromResource( |
247 unloaded_schemas_["webSocketProxyPrivate"] = ReadFromResource( | 376 IDR_EXTENSION_API_JSON_WEBREQUEST)); |
248 IDR_EXTENSION_API_JSON_WEBSOCKETPROXYPRIVATE); | 377 RegisterSchema("webSocketProxyPrivate", ReadFromResource( |
249 unloaded_schemas_["webstore"] = ReadFromResource( | 378 IDR_EXTENSION_API_JSON_WEBSOCKETPROXYPRIVATE)); |
250 IDR_EXTENSION_API_JSON_WEBSTORE); | 379 RegisterSchema("webstore", ReadFromResource( |
251 unloaded_schemas_["webstorePrivate"] = ReadFromResource( | 380 IDR_EXTENSION_API_JSON_WEBSTORE)); |
252 IDR_EXTENSION_API_JSON_WEBSTOREPRIVATE); | 381 RegisterSchema("webstorePrivate", ReadFromResource( |
253 unloaded_schemas_["windows"] = ReadFromResource( | 382 IDR_EXTENSION_API_JSON_WEBSTOREPRIVATE)); |
254 IDR_EXTENSION_API_JSON_WINDOWS); | 383 RegisterSchema("windows", ReadFromResource( |
| 384 IDR_EXTENSION_API_JSON_WINDOWS)); |
255 | 385 |
256 // Schemas to be loaded via JSON generated from IDL files. | 386 // Schemas to be loaded via JSON generated from IDL files. |
257 GeneratedSchemas::Get(&unloaded_schemas_); | 387 GeneratedSchemas::Get(&unloaded_schemas_); |
258 } | 388 |
259 | 389 LoadAllSchemas(); |
260 ExtensionAPI::~ExtensionAPI() { | 390 } |
| 391 |
| 392 void ExtensionAPI::RegisterSchema(const std::string& name, |
| 393 const base::StringPiece& source) { |
| 394 unloaded_schemas_[name] = source; |
| 395 } |
| 396 |
| 397 void ExtensionAPI::RegisterDependencyProvider(const std::string& name, |
| 398 FeatureProvider* provider) { |
| 399 dependency_providers_[name] = provider; |
| 400 } |
| 401 |
| 402 bool ExtensionAPI::IsAvailable(const std::string& full_name, |
| 403 const Extension* extension, |
| 404 Feature::Context context) { |
| 405 std::set<std::string> dependency_names; |
| 406 dependency_names.insert(full_name); |
| 407 ResolveDependencies(&dependency_names); |
| 408 |
| 409 for (std::set<std::string>::iterator iter = dependency_names.begin(); |
| 410 iter != dependency_names.end(); ++iter) { |
| 411 scoped_ptr<Feature> feature(GetFeatureDependency(full_name)); |
| 412 CHECK(feature.get()) << *iter; |
| 413 |
| 414 Feature::Availability availability = |
| 415 feature->IsAvailableToContext(extension, context); |
| 416 if (availability != Feature::IS_AVAILABLE) |
| 417 return false; |
| 418 } |
| 419 |
| 420 return true; |
261 } | 421 } |
262 | 422 |
263 bool ExtensionAPI::IsPrivileged(const std::string& full_name) { | 423 bool ExtensionAPI::IsPrivileged(const std::string& full_name) { |
264 std::string api_name; | |
265 std::string child_name; | 424 std::string child_name; |
266 | 425 std::string api_name = GetAPINameFromFullName(full_name, &child_name); |
267 { | |
268 std::vector<std::string> split; | |
269 base::SplitString(full_name, '.', &split); | |
270 std::reverse(split.begin(), split.end()); | |
271 CHECK(!split.empty()); // |full_name| was empty or only whitespace. | |
272 | |
273 api_name = split.back(); | |
274 split.pop_back(); | |
275 if (api_name == "experimental") { | |
276 CHECK(!split.empty()); // |full_name| was "experimental" alone. | |
277 api_name += "." + split.back(); | |
278 split.pop_back(); | |
279 } | |
280 | |
281 // This only really works properly if split.size() == 1, however: | |
282 // - if it's empty, it's ok to leave child_name empty; presumably there's | |
283 // no functions or events with empty names. | |
284 // - if it's > 1, we can just do our best. | |
285 if (split.size() > 0) | |
286 child_name = split[0]; | |
287 } | |
288 | 426 |
289 // GetSchema to ensure that it gets loaded before any checks. | 427 // GetSchema to ensure that it gets loaded before any checks. |
290 const DictionaryValue* schema = GetSchema(api_name); | 428 const DictionaryValue* schema = GetSchema(api_name); |
291 | 429 if (api_name.empty() || !schema) |
| 430 return true; // default to privileged for paranoia's sake. |
| 431 |
| 432 // First try to use the feature system. |
| 433 scoped_ptr<Feature> feature(GetFeature(full_name)); |
| 434 if (feature.get()) { |
| 435 // An API is 'privileged' if it or any of its dependencies can only be run |
| 436 // in a blessed context. |
| 437 std::set<std::string> resolved_dependencies; |
| 438 resolved_dependencies.insert(full_name); |
| 439 ResolveDependencies(&resolved_dependencies); |
| 440 for (std::set<std::string>::iterator iter = resolved_dependencies.begin(); |
| 441 iter != resolved_dependencies.end(); ++iter) { |
| 442 scoped_ptr<Feature> dependency(GetFeatureDependency(*iter)); |
| 443 for (std::set<Feature::Context>::iterator context = |
| 444 dependency->contexts()->begin(); |
| 445 context != dependency->contexts()->end(); ++context) { |
| 446 if (*context != Feature::BLESSED_EXTENSION_CONTEXT) |
| 447 return false; |
| 448 } |
| 449 } |
| 450 return true; |
| 451 } |
| 452 |
| 453 // If this API hasn't been converted yet, fall back to the old system. |
292 if (completely_unprivileged_apis_.count(api_name)) | 454 if (completely_unprivileged_apis_.count(api_name)) |
293 return false; | 455 return false; |
294 | 456 |
295 if (partially_unprivileged_apis_.count(api_name)) { | 457 if (partially_unprivileged_apis_.count(api_name)) |
296 return IsChildNamePrivileged(schema, "functions", child_name) && | 458 return IsChildNamePrivileged(schema, child_name); |
297 IsChildNamePrivileged(schema, "events", child_name); | |
298 } | |
299 | 459 |
300 return true; | 460 return true; |
301 } | 461 } |
302 | 462 |
303 DictionaryValue* ExtensionAPI::FindListItem( | |
304 const ListValue* list, | |
305 const std::string& property_name, | |
306 const std::string& property_value) { | |
307 for (size_t i = 0; i < list->GetSize(); ++i) { | |
308 DictionaryValue* item = NULL; | |
309 CHECK(list->GetDictionary(i, &item)) | |
310 << property_value << "/" << property_name; | |
311 std::string value; | |
312 if (item->GetString(property_name, &value) && value == property_value) | |
313 return item; | |
314 } | |
315 | |
316 return NULL; | |
317 } | |
318 | |
319 bool ExtensionAPI::IsChildNamePrivileged(const DictionaryValue* name_space_node, | 463 bool ExtensionAPI::IsChildNamePrivileged(const DictionaryValue* name_space_node, |
320 const std::string& child_kind, | |
321 const std::string& child_name) { | 464 const std::string& child_name) { |
322 ListValue* child_list = NULL; | |
323 name_space_node->GetList(child_kind, &child_list); | |
324 if (!child_list) | |
325 return true; | |
326 | |
327 bool unprivileged = false; | 465 bool unprivileged = false; |
328 DictionaryValue* child = FindListItem(child_list, "name", child_name); | 466 const DictionaryValue* child = GetSchemaChild(name_space_node, child_name); |
329 if (!child || !child->GetBoolean("unprivileged", &unprivileged)) | 467 if (!child || !child->GetBoolean("unprivileged", &unprivileged)) |
330 return true; | 468 return true; |
331 | 469 |
332 return !unprivileged; | 470 return !unprivileged; |
333 } | 471 } |
334 | 472 |
335 const DictionaryValue* ExtensionAPI::GetSchema(const std::string& api_name) { | 473 const DictionaryValue* ExtensionAPI::GetSchema(const std::string& full_name) { |
336 SchemaMap::const_iterator maybe_schema = schemas_.find(api_name); | 474 std::string child_name; |
337 if (maybe_schema != schemas_.end()) | 475 std::string api_name = GetAPINameFromFullName(full_name, &child_name); |
338 return maybe_schema->second.get(); | 476 |
339 | 477 const DictionaryValue* result = NULL; |
340 // Might not have loaded yet; or might just not exist. | 478 SchemaMap::iterator maybe_schema = schemas_.find(api_name); |
341 std::map<std::string, base::StringPiece>::iterator maybe_schema_resource = | 479 if (maybe_schema != schemas_.end()) { |
342 unloaded_schemas_.find(api_name); | 480 result = maybe_schema->second.get(); |
343 if (maybe_schema_resource == unloaded_schemas_.end()) | 481 } else { |
344 return NULL; | 482 // Might not have loaded yet; or might just not exist. |
345 | 483 std::map<std::string, base::StringPiece>::iterator maybe_schema_resource = |
346 LoadSchema(maybe_schema_resource->second); | 484 unloaded_schemas_.find(api_name); |
347 maybe_schema = schemas_.find(api_name); | 485 if (maybe_schema_resource == unloaded_schemas_.end()) |
348 CHECK(schemas_.end() != maybe_schema); | 486 return NULL; |
349 return maybe_schema->second.get(); | 487 |
| 488 LoadSchema(maybe_schema_resource->second); |
| 489 maybe_schema = schemas_.find(api_name); |
| 490 CHECK(schemas_.end() != maybe_schema); |
| 491 result = maybe_schema->second.get(); |
| 492 } |
| 493 |
| 494 if (!child_name.empty()) |
| 495 result = GetSchemaChild(result, child_name); |
| 496 |
| 497 return result; |
350 } | 498 } |
351 | 499 |
352 scoped_ptr<std::set<std::string> > ExtensionAPI::GetAPIsForContext( | 500 scoped_ptr<std::set<std::string> > ExtensionAPI::GetAPIsForContext( |
353 Feature::Context context, const Extension* extension, const GURL& url) { | 501 Feature::Context context, const Extension* extension, const GURL& url) { |
354 // We're forced to load all schemas now because we need to know the metadata | 502 std::set<std::string> temp_result; |
355 // about every API -- and the metadata is stored in the schemas themselves. | 503 |
356 // This is a shame. | 504 // First handle all the APIs that have been converted to the feature system. |
357 // TODO(aa/kalman): store metadata in a separate file and don't load all | 505 if (extension) { |
358 // schemas. | 506 for (APIFeatureMap::iterator iter = features_.begin(); |
359 LoadAllSchemas(); | 507 iter != features_.end(); ++iter) { |
360 | 508 if (IsAvailable(iter->first, extension, context)) |
361 scoped_ptr<std::set<std::string> > result(new std::set<std::string>()); | 509 temp_result.insert(iter->first); |
362 | 510 } |
| 511 } |
| 512 |
| 513 // Second, fall back to the old way. |
| 514 // TODO(aa): Remove this when all APIs have been converted. |
363 switch (context) { | 515 switch (context) { |
364 case Feature::UNSPECIFIED_CONTEXT: | 516 case Feature::UNSPECIFIED_CONTEXT: |
365 break; | 517 break; |
366 | 518 |
367 case Feature::BLESSED_EXTENSION_CONTEXT: | 519 case Feature::BLESSED_EXTENSION_CONTEXT: |
368 // Availability is determined by the permissions of the extension. | 520 // Availability is determined by the permissions of the extension. |
369 CHECK(extension); | 521 CHECK(extension); |
370 GetAllowedAPIs(extension, result.get()); | 522 GetAllowedAPIs(extension, &temp_result); |
371 ResolveDependencies(result.get()); | 523 ResolveDependencies(&temp_result); |
372 break; | 524 break; |
373 | 525 |
374 case Feature::UNBLESSED_EXTENSION_CONTEXT: | 526 case Feature::UNBLESSED_EXTENSION_CONTEXT: |
375 case Feature::CONTENT_SCRIPT_CONTEXT: | 527 case Feature::CONTENT_SCRIPT_CONTEXT: |
376 // Same as BLESSED_EXTENSION_CONTEXT, but only those APIs that are | 528 // Same as BLESSED_EXTENSION_CONTEXT, but only those APIs that are |
377 // unprivileged. | 529 // unprivileged. |
378 CHECK(extension); | 530 CHECK(extension); |
379 GetAllowedAPIs(extension, result.get()); | 531 GetAllowedAPIs(extension, &temp_result); |
380 // Resolving dependencies before removing unprivileged APIs means that | 532 // Resolving dependencies before removing unprivileged APIs means that |
381 // some unprivileged APIs may have unrealised dependencies. Too bad! | 533 // some unprivileged APIs may have unrealised dependencies. Too bad! |
382 ResolveDependencies(result.get()); | 534 ResolveDependencies(&temp_result); |
383 RemovePrivilegedAPIs(result.get()); | 535 RemovePrivilegedAPIs(&temp_result); |
384 break; | 536 break; |
385 | 537 |
386 case Feature::WEB_PAGE_CONTEXT: | 538 case Feature::WEB_PAGE_CONTEXT: |
387 // Availablility is determined by the url. | 539 // Availablility is determined by the url. |
388 CHECK(url.is_valid()); | 540 CHECK(url.is_valid()); |
389 GetAPIsMatchingURL(url, result.get()); | 541 GetAPIsMatchingURL(url, &temp_result); |
390 break; | 542 break; |
391 } | 543 } |
392 | 544 |
| 545 // Filter out all non-API features and remove the feature type part of the |
| 546 // name. |
| 547 scoped_ptr<std::set<std::string> > result(new std::set<std::string>()); |
| 548 for (std::set<std::string>::iterator iter = temp_result.begin(); |
| 549 iter != temp_result.end(); ++iter) { |
| 550 std::string feature_type; |
| 551 std::string feature_name; |
| 552 SplitDependencyName(*iter, &feature_type, &feature_name); |
| 553 if (feature_type == "api") |
| 554 result->insert(feature_name); |
| 555 } |
| 556 |
393 return result.Pass(); | 557 return result.Pass(); |
394 } | 558 } |
395 | 559 |
| 560 scoped_ptr<Feature> ExtensionAPI::GetFeature(const std::string& full_name) { |
| 561 std::string child_name; |
| 562 std::string api_namespace = GetAPINameFromFullName(full_name, &child_name); |
| 563 |
| 564 APIFeatureMap::iterator api_features = features_.find(api_namespace); |
| 565 if (api_features == features_.end()) |
| 566 return scoped_ptr<Feature>(NULL); |
| 567 |
| 568 scoped_ptr<Feature> result; |
| 569 FeatureMap::iterator child_feature = api_features->second->find(child_name); |
| 570 if (child_feature != api_features->second->end()) { |
| 571 // TODO(aa): Argh, having FeatureProvider return a scoped pointer was a |
| 572 // mistake. See: crbug.com/120068. |
| 573 result.reset(new Feature(*child_feature->second)); |
| 574 } else { |
| 575 FeatureMap::iterator parent_feature = api_features->second->find(""); |
| 576 CHECK(parent_feature != api_features->second->end()); |
| 577 result.reset(new Feature(*parent_feature->second)); |
| 578 } |
| 579 |
| 580 if (result->contexts()->empty()) { |
| 581 result.reset(); |
| 582 LOG(ERROR) << "API feature '" << full_name |
| 583 << "' must specify at least one context."; |
| 584 } |
| 585 |
| 586 return result.Pass(); |
| 587 } |
| 588 |
| 589 scoped_ptr<Feature> ExtensionAPI::GetFeatureDependency( |
| 590 const std::string& full_name) { |
| 591 std::string feature_type; |
| 592 std::string feature_name; |
| 593 SplitDependencyName(full_name, &feature_type, &feature_name); |
| 594 |
| 595 FeatureProviderMap::iterator provider = |
| 596 dependency_providers_.find(feature_type); |
| 597 CHECK(provider != dependency_providers_.end()) << full_name; |
| 598 |
| 599 scoped_ptr<Feature> feature(provider->second->GetFeature(feature_name)); |
| 600 CHECK(feature.get()) << full_name; |
| 601 |
| 602 return feature.Pass(); |
| 603 } |
| 604 |
| 605 std::string ExtensionAPI::GetAPINameFromFullName(const std::string& full_name, |
| 606 std::string* child_name) { |
| 607 std::string api_name_candidate = full_name; |
| 608 while (true) { |
| 609 if (features_.find(api_name_candidate) != features_.end() || |
| 610 schemas_.find(api_name_candidate) != schemas_.end() || |
| 611 unloaded_schemas_.find(api_name_candidate) != unloaded_schemas_.end()) { |
| 612 std::string result = api_name_candidate; |
| 613 |
| 614 if (child_name) { |
| 615 if (result.length() < full_name.length()) |
| 616 *child_name = full_name.substr(result.length() + 1); |
| 617 else |
| 618 *child_name = ""; |
| 619 } |
| 620 |
| 621 return result; |
| 622 } |
| 623 |
| 624 size_t last_dot_index = api_name_candidate.rfind('.'); |
| 625 if (last_dot_index == std::string::npos) |
| 626 break; |
| 627 |
| 628 api_name_candidate = api_name_candidate.substr(0, last_dot_index); |
| 629 } |
| 630 |
| 631 *child_name = ""; |
| 632 return ""; |
| 633 } |
| 634 |
396 void ExtensionAPI::GetAllowedAPIs( | 635 void ExtensionAPI::GetAllowedAPIs( |
397 const Extension* extension, std::set<std::string>* out) { | 636 const Extension* extension, std::set<std::string>* out) { |
398 for (SchemaMap::const_iterator i = schemas_.begin(); i != schemas_.end(); | 637 for (SchemaMap::const_iterator i = schemas_.begin(); i != schemas_.end(); |
399 ++i) { | 638 ++i) { |
| 639 if (features_.find(i->first) != features_.end()) { |
| 640 // This API is controlled by the feature system. Nothing to do here. |
| 641 continue; |
| 642 } |
| 643 |
400 if (extension->required_permission_set()->HasAnyAccessToAPI(i->first) || | 644 if (extension->required_permission_set()->HasAnyAccessToAPI(i->first) || |
401 extension->optional_permission_set()->HasAnyAccessToAPI(i->first)) { | 645 extension->optional_permission_set()->HasAnyAccessToAPI(i->first)) { |
402 out->insert(i->first); | 646 out->insert(i->first); |
403 } | 647 } |
404 } | 648 } |
405 } | 649 } |
406 | 650 |
407 void ExtensionAPI::ResolveDependencies(std::set<std::string>* out) { | 651 void ExtensionAPI::ResolveDependencies(std::set<std::string>* out) { |
408 std::set<std::string> missing_dependencies; | 652 std::set<std::string> missing_dependencies; |
409 for (std::set<std::string>::iterator i = out->begin(); i != out->end(); ++i) | 653 for (std::set<std::string>::iterator i = out->begin(); i != out->end(); ++i) |
410 GetMissingDependencies(*i, *out, &missing_dependencies); | 654 GetMissingDependencies(*i, *out, &missing_dependencies); |
411 | 655 |
412 while (missing_dependencies.size()) { | 656 while (missing_dependencies.size()) { |
413 std::string next = *missing_dependencies.begin(); | 657 std::string next = *missing_dependencies.begin(); |
414 missing_dependencies.erase(next); | 658 missing_dependencies.erase(next); |
415 out->insert(next); | 659 out->insert(next); |
416 GetMissingDependencies(next, *out, &missing_dependencies); | 660 GetMissingDependencies(next, *out, &missing_dependencies); |
417 } | 661 } |
418 } | 662 } |
419 | 663 |
420 void ExtensionAPI::GetMissingDependencies( | 664 void ExtensionAPI::GetMissingDependencies( |
421 const std::string& api_name, | 665 const std::string& api_name, |
422 const std::set<std::string>& excluding, | 666 const std::set<std::string>& excluding, |
423 std::set<std::string>* out) { | 667 std::set<std::string>* out) { |
424 const DictionaryValue* schema = GetSchema(api_name); | 668 std::string feature_type; |
425 CHECK(schema) << "Schema for " << api_name << " not found"; | 669 std::string feature_name; |
| 670 SplitDependencyName(api_name, &feature_type, &feature_name); |
| 671 |
| 672 // Only API features can have dependencies for now. |
| 673 if (feature_type != "api") |
| 674 return; |
| 675 |
| 676 const DictionaryValue* schema = GetSchema(feature_name); |
| 677 CHECK(schema) << "Schema for " << feature_name << " not found"; |
426 | 678 |
427 ListValue* dependencies = NULL; | 679 ListValue* dependencies = NULL; |
428 if (!schema->GetList("dependencies", &dependencies)) | 680 if (!schema->GetList("dependencies", &dependencies)) |
429 return; | 681 return; |
430 | 682 |
431 for (size_t i = 0; i < dependencies->GetSize(); ++i) { | 683 for (size_t i = 0; i < dependencies->GetSize(); ++i) { |
432 std::string api_name; | 684 std::string dependency_name; |
433 if (dependencies->GetString(i, &api_name) && !excluding.count(api_name)) | 685 if (dependencies->GetString(i, &dependency_name) && |
434 out->insert(api_name); | 686 !excluding.count(dependency_name)) { |
| 687 out->insert(dependency_name); |
| 688 } |
435 } | 689 } |
436 } | 690 } |
437 | 691 |
438 void ExtensionAPI::RemovePrivilegedAPIs(std::set<std::string>* apis) { | 692 void ExtensionAPI::RemovePrivilegedAPIs(std::set<std::string>* apis) { |
439 std::set<std::string> privileged_apis; | 693 std::set<std::string> privileged_apis; |
440 for (std::set<std::string>::iterator i = apis->begin(); i != apis->end(); | 694 for (std::set<std::string>::iterator i = apis->begin(); i != apis->end(); |
441 ++i) { | 695 ++i) { |
442 if (!completely_unprivileged_apis_.count(*i) && | 696 if (!completely_unprivileged_apis_.count(*i) && |
443 !partially_unprivileged_apis_.count(*i)) { | 697 !partially_unprivileged_apis_.count(*i)) { |
444 privileged_apis.insert(*i); | 698 privileged_apis.insert(*i); |
445 } | 699 } |
446 } | 700 } |
447 for (std::set<std::string>::iterator i = privileged_apis.begin(); | 701 for (std::set<std::string>::iterator i = privileged_apis.begin(); |
448 i != privileged_apis.end(); ++i) { | 702 i != privileged_apis.end(); ++i) { |
449 apis->erase(*i); | 703 apis->erase(*i); |
450 } | 704 } |
451 } | 705 } |
452 | 706 |
453 void ExtensionAPI::GetAPIsMatchingURL(const GURL& url, | 707 void ExtensionAPI::GetAPIsMatchingURL(const GURL& url, |
454 std::set<std::string>* out) { | 708 std::set<std::string>* out) { |
455 for (std::map<std::string, URLPatternSet>::const_iterator i = | 709 for (std::map<std::string, URLPatternSet>::const_iterator i = |
456 url_matching_apis_.begin(); i != url_matching_apis_.end(); ++i) { | 710 url_matching_apis_.begin(); i != url_matching_apis_.end(); ++i) { |
| 711 if (features_.find(i->first) != features_.end()) { |
| 712 // This API is controlled by the feature system. Nothing to do. |
| 713 continue; |
| 714 } |
| 715 |
457 if (i->second.MatchesURL(url)) | 716 if (i->second.MatchesURL(url)) |
458 out->insert(i->first); | 717 out->insert(i->first); |
459 } | 718 } |
460 } | 719 } |
461 | 720 |
462 void ExtensionAPI::LoadAllSchemas() { | 721 void ExtensionAPI::LoadAllSchemas() { |
463 while (unloaded_schemas_.size()) { | 722 while (unloaded_schemas_.size()) { |
464 LoadSchema(unloaded_schemas_.begin()->second); | 723 LoadSchema(unloaded_schemas_.begin()->second); |
465 } | 724 } |
466 } | 725 } |
467 | 726 |
468 } // namespace extensions | 727 } // namespace extensions |
OLD | NEW |