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

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

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

Powered by Google App Engine
This is Rietveld 408576698