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

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

Powered by Google App Engine
This is Rietveld 408576698