Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(62)

Side by Side Diff: chrome/common/extensions/api/extension_api.cc

Issue 9969136: Reland r130462: Implement FeatureProvider for ExtensionAPI." (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Replace lazy-loading of schemas. I removed this accidentally in my first patch. Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
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
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(ExtensionAPI::CreateWithDefaultConfiguration()) {
112 }
113 scoped_ptr<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.get();
Matt Perry 2012/04/04 16:40:22 maybe we should DCHECK that this is the UI thread
Aaron Boodman 2012/04/04 18:05:42 Good idea. Done.
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
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
260 ExtensionAPI::~ExtensionAPI() { 390 void ExtensionAPI::RegisterSchema(const std::string& name,
391 const base::StringPiece& source) {
392 unloaded_schemas_[name] = source;
393 }
394
395 void ExtensionAPI::RegisterDependencyProvider(const std::string& name,
396 FeatureProvider* provider) {
397 dependency_providers_[name] = provider;
398 }
399
400 bool ExtensionAPI::IsAvailable(const std::string& full_name,
401 const Extension* extension,
402 Feature::Context context) {
403 std::set<std::string> dependency_names;
404 dependency_names.insert(full_name);
405 ResolveDependencies(&dependency_names);
406
407 for (std::set<std::string>::iterator iter = dependency_names.begin();
408 iter != dependency_names.end(); ++iter) {
409 scoped_ptr<Feature> feature(GetFeatureDependency(full_name));
410 CHECK(feature.get()) << *iter;
411
412 Feature::Availability availability =
413 feature->IsAvailableToContext(extension, context);
414 if (availability != Feature::IS_AVAILABLE)
415 return false;
416 }
417
418 return true;
261 } 419 }
262 420
263 bool ExtensionAPI::IsPrivileged(const std::string& full_name) { 421 bool ExtensionAPI::IsPrivileged(const std::string& full_name) {
264 std::string api_name;
265 std::string child_name; 422 std::string child_name;
266 423 std::string api_name = GetAPINameFromFullName(full_name, &child_name);
267 { 424
268 std::vector<std::string> split; 425 // First try to use the feature system.
269 base::SplitString(full_name, '.', &split); 426 scoped_ptr<Feature> feature(GetFeature(full_name));
270 std::reverse(split.begin(), split.end()); 427 if (feature.get()) {
271 CHECK(!split.empty()); // |full_name| was empty or only whitespace. 428 // An API is 'privileged' if it or any of its dependencies can only be run
272 429 // in a blessed context.
273 api_name = split.back(); 430 std::set<std::string> resolved_dependencies;
274 split.pop_back(); 431 resolved_dependencies.insert(full_name);
275 if (api_name == "experimental") { 432 ResolveDependencies(&resolved_dependencies);
276 CHECK(!split.empty()); // |full_name| was "experimental" alone. 433 for (std::set<std::string>::iterator iter = resolved_dependencies.begin();
277 api_name += "." + split.back(); 434 iter != resolved_dependencies.end(); ++iter) {
278 split.pop_back(); 435 scoped_ptr<Feature> dependency(GetFeatureDependency(*iter));
436 for (std::set<Feature::Context>::iterator context =
437 dependency->contexts()->begin();
438 context != dependency->contexts()->end(); ++context) {
439 if (*context != Feature::BLESSED_EXTENSION_CONTEXT)
440 return false;
441 }
279 } 442 }
280 443 return true;
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 } 444 }
288 445
289 // GetSchema to ensure that it gets loaded before any checks. 446 // If this API hasn't been converted yet, fall back to the old system.
290 const DictionaryValue* schema = GetSchema(api_name);
291
292 if (completely_unprivileged_apis_.count(api_name)) 447 if (completely_unprivileged_apis_.count(api_name))
293 return false; 448 return false;
294 449
295 if (partially_unprivileged_apis_.count(api_name)) { 450 const DictionaryValue* schema = GetSchema(api_name);
296 return IsChildNamePrivileged(schema, "functions", child_name) && 451 if (partially_unprivileged_apis_.count(api_name))
297 IsChildNamePrivileged(schema, "events", child_name); 452 return IsChildNamePrivileged(schema, child_name);
298 }
299 453
300 return true; 454 return true;
301 } 455 }
302 456
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, 457 bool ExtensionAPI::IsChildNamePrivileged(const DictionaryValue* name_space_node,
320 const std::string& child_kind,
321 const std::string& child_name) { 458 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; 459 bool unprivileged = false;
328 DictionaryValue* child = FindListItem(child_list, "name", child_name); 460 const DictionaryValue* child = GetSchemaChild(name_space_node, child_name);
329 if (!child || !child->GetBoolean("unprivileged", &unprivileged)) 461 if (!child || !child->GetBoolean("unprivileged", &unprivileged))
330 return true; 462 return true;
331 463
332 return !unprivileged; 464 return !unprivileged;
333 } 465 }
334 466
335 const DictionaryValue* ExtensionAPI::GetSchema(const std::string& api_name) { 467 const DictionaryValue* ExtensionAPI::GetSchema(const std::string& full_name) {
336 SchemaMap::const_iterator maybe_schema = schemas_.find(api_name); 468 std::string child_name;
337 if (maybe_schema != schemas_.end()) 469 std::string api_name = GetAPINameFromFullName(full_name, &child_name);
338 return maybe_schema->second.get(); 470
339 471 const DictionaryValue* result = NULL;
340 // Might not have loaded yet; or might just not exist. 472 SchemaMap::iterator maybe_schema = schemas_.find(api_name);
341 std::map<std::string, base::StringPiece>::iterator maybe_schema_resource = 473 if (maybe_schema != schemas_.end()) {
342 unloaded_schemas_.find(api_name); 474 result = maybe_schema->second.get();
343 if (maybe_schema_resource == unloaded_schemas_.end()) 475 } else {
344 return NULL; 476 // Might not have loaded yet; or might just not exist.
345 477 std::map<std::string, base::StringPiece>::iterator maybe_schema_resource =
346 LoadSchema(maybe_schema_resource->second); 478 unloaded_schemas_.find(api_name);
347 maybe_schema = schemas_.find(api_name); 479 if (maybe_schema_resource == unloaded_schemas_.end())
348 CHECK(schemas_.end() != maybe_schema); 480 return NULL;
349 return maybe_schema->second.get(); 481
482 LoadSchema(maybe_schema_resource->second);
483 maybe_schema = schemas_.find(api_name);
484 CHECK(schemas_.end() != maybe_schema);
485 result = maybe_schema->second.get();
486 }
487
488 if (!child_name.empty())
489 result = GetSchemaChild(result, child_name);
490
491 return result;
350 } 492 }
351 493
352 scoped_ptr<std::set<std::string> > ExtensionAPI::GetAPIsForContext( 494 scoped_ptr<std::set<std::string> > ExtensionAPI::GetAPIsForContext(
353 Feature::Context context, const Extension* extension, const GURL& url) { 495 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 496 // We're forced to load all schemas now because we need to know the metadata
355 // about every API -- and the metadata is stored in the schemas themselves. 497 // about every API -- and the metadata is stored in the schemas themselves.
356 // This is a shame. 498 // This is a shame.
357 // TODO(aa/kalman): store metadata in a separate file and don't load all 499 // TODO(aa/kalman): store metadata in a separate file and don't load all
358 // schemas. 500 // schemas.
359 LoadAllSchemas(); 501 LoadAllSchemas();
360 502
361 scoped_ptr<std::set<std::string> > result(new std::set<std::string>()); 503 std::set<std::string> temp_result;
362 504
505 // First handle all the APIs that have been converted to the feature system.
506 if (extension) {
507 for (APIFeatureMap::iterator iter = features_.begin();
508 iter != features_.end(); ++iter) {
509 if (IsAvailable(iter->first, extension, context))
510 temp_result.insert(iter->first);
511 }
512 }
513
514 // Second, fall back to the old way.
515 // TODO(aa): Remove this when all APIs have been converted.
363 switch (context) { 516 switch (context) {
364 case Feature::UNSPECIFIED_CONTEXT: 517 case Feature::UNSPECIFIED_CONTEXT:
365 break; 518 break;
366 519
367 case Feature::BLESSED_EXTENSION_CONTEXT: 520 case Feature::BLESSED_EXTENSION_CONTEXT:
368 // Availability is determined by the permissions of the extension. 521 // Availability is determined by the permissions of the extension.
369 CHECK(extension); 522 CHECK(extension);
370 GetAllowedAPIs(extension, result.get()); 523 GetAllowedAPIs(extension, &temp_result);
371 ResolveDependencies(result.get()); 524 ResolveDependencies(&temp_result);
372 break; 525 break;
373 526
374 case Feature::UNBLESSED_EXTENSION_CONTEXT: 527 case Feature::UNBLESSED_EXTENSION_CONTEXT:
375 case Feature::CONTENT_SCRIPT_CONTEXT: 528 case Feature::CONTENT_SCRIPT_CONTEXT:
376 // Same as BLESSED_EXTENSION_CONTEXT, but only those APIs that are 529 // Same as BLESSED_EXTENSION_CONTEXT, but only those APIs that are
377 // unprivileged. 530 // unprivileged.
378 CHECK(extension); 531 CHECK(extension);
379 GetAllowedAPIs(extension, result.get()); 532 GetAllowedAPIs(extension, &temp_result);
380 // Resolving dependencies before removing unprivileged APIs means that 533 // Resolving dependencies before removing unprivileged APIs means that
381 // some unprivileged APIs may have unrealised dependencies. Too bad! 534 // some unprivileged APIs may have unrealised dependencies. Too bad!
382 ResolveDependencies(result.get()); 535 ResolveDependencies(&temp_result);
383 RemovePrivilegedAPIs(result.get()); 536 RemovePrivilegedAPIs(&temp_result);
384 break; 537 break;
385 538
386 case Feature::WEB_PAGE_CONTEXT: 539 case Feature::WEB_PAGE_CONTEXT:
387 // Availablility is determined by the url. 540 // Availablility is determined by the url.
388 CHECK(url.is_valid()); 541 CHECK(url.is_valid());
389 GetAPIsMatchingURL(url, result.get()); 542 GetAPIsMatchingURL(url, &temp_result);
390 break; 543 break;
391 } 544 }
392 545
546 // Filter out all non-API features and remove the feature type part of the
547 // name.
548 scoped_ptr<std::set<std::string> > result(new std::set<std::string>());
549 for (std::set<std::string>::iterator iter = temp_result.begin();
550 iter != temp_result.end(); ++iter) {
551 std::string feature_type;
552 std::string feature_name;
553 SplitDependencyName(*iter, &feature_type, &feature_name);
554 if (feature_type == "api")
555 result->insert(feature_name);
556 }
557
393 return result.Pass(); 558 return result.Pass();
394 } 559 }
395 560
561 scoped_ptr<Feature> ExtensionAPI::GetFeature(const std::string& full_name) {
562 // Ensure it's loaded.
563 GetSchema(full_name);
564
565 std::string child_name;
566 std::string api_namespace = GetAPINameFromFullName(full_name, &child_name);
567
568 APIFeatureMap::iterator api_features = features_.find(api_namespace);
569 if (api_features == features_.end())
570 return scoped_ptr<Feature>(NULL);
571
572 scoped_ptr<Feature> result;
573 FeatureMap::iterator child_feature = api_features->second->find(child_name);
574 if (child_feature != api_features->second->end()) {
575 // TODO(aa): Argh, having FeatureProvider return a scoped pointer was a
576 // mistake. See: crbug.com/120068.
577 result.reset(new Feature(*child_feature->second));
578 } else {
579 FeatureMap::iterator parent_feature = api_features->second->find("");
580 CHECK(parent_feature != api_features->second->end());
581 result.reset(new Feature(*parent_feature->second));
582 }
583
584 if (result->contexts()->empty()) {
585 result.reset();
586 LOG(ERROR) << "API feature '" << full_name
587 << "' must specify at least one context.";
588 }
589
590 return result.Pass();
591 }
592
593 scoped_ptr<Feature> ExtensionAPI::GetFeatureDependency(
594 const std::string& full_name) {
595 std::string feature_type;
596 std::string feature_name;
597 SplitDependencyName(full_name, &feature_type, &feature_name);
598
599 FeatureProviderMap::iterator provider =
600 dependency_providers_.find(feature_type);
601 CHECK(provider != dependency_providers_.end()) << full_name;
602
603 scoped_ptr<Feature> feature(provider->second->GetFeature(feature_name));
604 CHECK(feature.get()) << full_name;
605
606 return feature.Pass();
607 }
608
609 std::string ExtensionAPI::GetAPINameFromFullName(const std::string& full_name,
610 std::string* child_name) {
611 std::string api_name_candidate = full_name;
612 while (true) {
613 if (features_.find(api_name_candidate) != features_.end() ||
614 schemas_.find(api_name_candidate) != schemas_.end() ||
615 unloaded_schemas_.find(api_name_candidate) != unloaded_schemas_.end()) {
616 std::string result = api_name_candidate;
617
618 if (child_name) {
619 if (result.length() < full_name.length())
620 *child_name = full_name.substr(result.length() + 1);
621 else
622 *child_name = "";
623 }
624
625 return result;
626 }
627
628 size_t last_dot_index = api_name_candidate.rfind('.');
629 if (last_dot_index == std::string::npos)
630 break;
631
632 api_name_candidate = api_name_candidate.substr(0, last_dot_index);
633 }
634
635 *child_name = "";
636 return "";
637 }
638
396 void ExtensionAPI::GetAllowedAPIs( 639 void ExtensionAPI::GetAllowedAPIs(
397 const Extension* extension, std::set<std::string>* out) { 640 const Extension* extension, std::set<std::string>* out) {
398 for (SchemaMap::const_iterator i = schemas_.begin(); i != schemas_.end(); 641 for (SchemaMap::const_iterator i = schemas_.begin(); i != schemas_.end();
399 ++i) { 642 ++i) {
643 if (features_.find(i->first) != features_.end()) {
644 // This API is controlled by the feature system. Nothing to do here.
645 continue;
646 }
647
400 if (extension->required_permission_set()->HasAnyAccessToAPI(i->first) || 648 if (extension->required_permission_set()->HasAnyAccessToAPI(i->first) ||
401 extension->optional_permission_set()->HasAnyAccessToAPI(i->first)) { 649 extension->optional_permission_set()->HasAnyAccessToAPI(i->first)) {
402 out->insert(i->first); 650 out->insert(i->first);
403 } 651 }
404 } 652 }
405 } 653 }
406 654
407 void ExtensionAPI::ResolveDependencies(std::set<std::string>* out) { 655 void ExtensionAPI::ResolveDependencies(std::set<std::string>* out) {
408 std::set<std::string> missing_dependencies; 656 std::set<std::string> missing_dependencies;
409 for (std::set<std::string>::iterator i = out->begin(); i != out->end(); ++i) 657 for (std::set<std::string>::iterator i = out->begin(); i != out->end(); ++i)
410 GetMissingDependencies(*i, *out, &missing_dependencies); 658 GetMissingDependencies(*i, *out, &missing_dependencies);
411 659
412 while (missing_dependencies.size()) { 660 while (missing_dependencies.size()) {
413 std::string next = *missing_dependencies.begin(); 661 std::string next = *missing_dependencies.begin();
414 missing_dependencies.erase(next); 662 missing_dependencies.erase(next);
415 out->insert(next); 663 out->insert(next);
416 GetMissingDependencies(next, *out, &missing_dependencies); 664 GetMissingDependencies(next, *out, &missing_dependencies);
417 } 665 }
418 } 666 }
419 667
420 void ExtensionAPI::GetMissingDependencies( 668 void ExtensionAPI::GetMissingDependencies(
421 const std::string& api_name, 669 const std::string& api_name,
422 const std::set<std::string>& excluding, 670 const std::set<std::string>& excluding,
423 std::set<std::string>* out) { 671 std::set<std::string>* out) {
424 const DictionaryValue* schema = GetSchema(api_name); 672 std::string feature_type;
425 CHECK(schema) << "Schema for " << api_name << " not found"; 673 std::string feature_name;
674 SplitDependencyName(api_name, &feature_type, &feature_name);
675
676 // Only API features can have dependencies for now.
677 if (feature_type != "api")
678 return;
679
680 const DictionaryValue* schema = GetSchema(feature_name);
681 CHECK(schema) << "Schema for " << feature_name << " not found";
426 682
427 ListValue* dependencies = NULL; 683 ListValue* dependencies = NULL;
428 if (!schema->GetList("dependencies", &dependencies)) 684 if (!schema->GetList("dependencies", &dependencies))
429 return; 685 return;
430 686
431 for (size_t i = 0; i < dependencies->GetSize(); ++i) { 687 for (size_t i = 0; i < dependencies->GetSize(); ++i) {
432 std::string api_name; 688 std::string dependency_name;
433 if (dependencies->GetString(i, &api_name) && !excluding.count(api_name)) 689 if (dependencies->GetString(i, &dependency_name) &&
434 out->insert(api_name); 690 !excluding.count(dependency_name)) {
691 out->insert(dependency_name);
692 }
435 } 693 }
436 } 694 }
437 695
438 void ExtensionAPI::RemovePrivilegedAPIs(std::set<std::string>* apis) { 696 void ExtensionAPI::RemovePrivilegedAPIs(std::set<std::string>* apis) {
439 std::set<std::string> privileged_apis; 697 std::set<std::string> privileged_apis;
440 for (std::set<std::string>::iterator i = apis->begin(); i != apis->end(); 698 for (std::set<std::string>::iterator i = apis->begin(); i != apis->end();
441 ++i) { 699 ++i) {
442 if (!completely_unprivileged_apis_.count(*i) && 700 if (!completely_unprivileged_apis_.count(*i) &&
443 !partially_unprivileged_apis_.count(*i)) { 701 !partially_unprivileged_apis_.count(*i)) {
444 privileged_apis.insert(*i); 702 privileged_apis.insert(*i);
445 } 703 }
446 } 704 }
447 for (std::set<std::string>::iterator i = privileged_apis.begin(); 705 for (std::set<std::string>::iterator i = privileged_apis.begin();
448 i != privileged_apis.end(); ++i) { 706 i != privileged_apis.end(); ++i) {
449 apis->erase(*i); 707 apis->erase(*i);
450 } 708 }
451 } 709 }
452 710
453 void ExtensionAPI::GetAPIsMatchingURL(const GURL& url, 711 void ExtensionAPI::GetAPIsMatchingURL(const GURL& url,
454 std::set<std::string>* out) { 712 std::set<std::string>* out) {
455 for (std::map<std::string, URLPatternSet>::const_iterator i = 713 for (std::map<std::string, URLPatternSet>::const_iterator i =
456 url_matching_apis_.begin(); i != url_matching_apis_.end(); ++i) { 714 url_matching_apis_.begin(); i != url_matching_apis_.end(); ++i) {
715 if (features_.find(i->first) != features_.end()) {
716 // This API is controlled by the feature system. Nothing to do.
717 continue;
718 }
719
457 if (i->second.MatchesURL(url)) 720 if (i->second.MatchesURL(url))
458 out->insert(i->first); 721 out->insert(i->first);
459 } 722 }
460 } 723 }
461 724
462 void ExtensionAPI::LoadAllSchemas() { 725 void ExtensionAPI::LoadAllSchemas() {
463 while (unloaded_schemas_.size()) { 726 while (unloaded_schemas_.size()) {
464 LoadSchema(unloaded_schemas_.begin()->second); 727 LoadSchema(unloaded_schemas_.begin()->second);
465 } 728 }
466 } 729 }
467 730
468 } // namespace extensions 731 } // namespace extensions
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698