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

Unified Diff: chrome/common/extensions/api/extension_api.cc

Issue 12522004: Lazily load extension API schemas (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 7 years, 9 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 side-by-side diff with in-line comments
Download patch
Index: chrome/common/extensions/api/extension_api.cc
diff --git a/chrome/common/extensions/api/extension_api.cc b/chrome/common/extensions/api/extension_api.cc
index c9988e55859afcf51739c3027444ac6cf5aab99c..c2a9cce97931c24a04b16ad3b7f1e8a911e57e13 100644
--- a/chrome/common/extensions/api/extension_api.cc
+++ b/chrome/common/extensions/api/extension_api.cc
@@ -36,6 +36,10 @@ using api::GeneratedSchemas;
namespace {
+const char kUnavailableMessage[] = "You do not have permission to access this "
+ "API. Ensure that the required permission "
+ "or manifest property is included in your "
+ "manifest.json.";
const char* kChildKinds[] = {
"functions",
"events"
@@ -230,6 +234,11 @@ void ExtensionAPI::SplitDependencyName(const std::string& full_name,
*feature_name = full_name.substr(colon_index + 1);
}
+bool ExtensionAPI::UsesFeatureSystem(const std::string& full_name) {
+ std::string api_name = GetAPINameFromFullName(full_name, NULL);
+ return features_.find(api_name) != features_.end();
+}
+
void ExtensionAPI::LoadSchema(const std::string& name,
const base::StringPiece& schema) {
scoped_ptr<ListValue> schema_list(LoadSchemaList(name, schema));
@@ -250,7 +259,7 @@ void ExtensionAPI::LoadSchema(const std::string& name,
CHECK_EQ(1u, unloaded_schemas_.erase(schema_namespace));
// Populate |{completely,partially}_unprivileged_apis_|.
- //
+
// For "partially", only need to look at functions/events; even though
// there are unprivileged properties (e.g. in extensions), access to those
// never reaches C++ land.
@@ -263,27 +272,28 @@ void ExtensionAPI::LoadSchema(const std::string& name,
partially_unprivileged_apis_.insert(schema_namespace);
}
- // Populate |url_matching_apis_|.
- ListValue* matches = NULL;
- if (schema->GetList("matches", &matches)) {
- URLPatternSet pattern_set;
- for (size_t i = 0; i < matches->GetSize(); ++i) {
- std::string pattern;
- CHECK(matches->GetString(i, &pattern));
- pattern_set.AddPattern(
- URLPattern(UserScript::ValidUserScriptSchemes(), pattern));
+ bool uses_feature_system = false;
+ schema->GetBoolean("uses_feature_system", &uses_feature_system);
+
+ if (!uses_feature_system) {
+ // Populate |url_matching_apis_|.
+ ListValue* matches = NULL;
+ if (schema->GetList("matches", &matches)) {
+ URLPatternSet pattern_set;
+ for (size_t i = 0; i < matches->GetSize(); ++i) {
+ std::string pattern;
+ CHECK(matches->GetString(i, &pattern));
+ pattern_set.AddPattern(
+ URLPattern(UserScript::ValidUserScriptSchemes(), pattern));
+ }
+ url_matching_apis_[schema_namespace] = pattern_set;
}
- url_matching_apis_[schema_namespace] = pattern_set;
+ continue;
}
// Populate feature maps.
// TODO(aa): Consider not storing features that can never run on the current
// machine (e.g., because of platform restrictions).
- bool uses_feature_system = false;
- schema->GetBoolean("uses_feature_system", &uses_feature_system);
- if (!uses_feature_system)
- continue;
-
SimpleFeature* feature = new SimpleFeature();
feature->set_name(schema_namespace);
feature->Parse(schema);
@@ -408,25 +418,34 @@ void ExtensionAPI::RegisterDependencyProvider(const std::string& name,
dependency_providers_[name] = provider;
}
-bool ExtensionAPI::IsAvailable(const std::string& full_name,
- const Extension* extension,
- Feature::Context context) {
+Feature::Availability ExtensionAPI::IsAvailable(const std::string& full_name,
+ const Extension* extension,
+ Feature::Context context,
+ const GURL& url) {
std::set<std::string> dependency_names;
dependency_names.insert(full_name);
ResolveDependencies(&dependency_names);
+ // Check APIs not using the feature system first.
+ if (!UsesFeatureSystem(full_name)) {
+ return IsNonFeatureAPIAvailable(full_name, context, extension, url) ?
+ Feature::CreateAvailability(Feature::IS_AVAILABLE, "") :
+ Feature::CreateAvailability(Feature::INVALID_CONTEXT,
+ kUnavailableMessage);
+ }
+
for (std::set<std::string>::iterator iter = dependency_names.begin();
iter != dependency_names.end(); ++iter) {
- Feature* feature = GetFeatureDependency(full_name);
+ Feature* feature = GetFeatureDependency(*iter);
CHECK(feature) << *iter;
Feature::Availability availability =
- feature->IsAvailableToContext(extension, context);
+ feature->IsAvailableToContext(extension, context, url);
if (!availability.is_available())
- return false;
+ return availability;
}
- return true;
+ return Feature::CreateAvailability(Feature::IS_AVAILABLE, "");
}
bool ExtensionAPI::IsPrivileged(const std::string& full_name) {
@@ -524,46 +543,12 @@ bool IsFeatureAllowedForExtension(const std::string& feature,
return true;
}
-// Removes APIs from |apis| that should not be allowed for |extension|.
-// TODO(kalman/asargent) - Make it possible to specify these rules
-// declaratively.
-void RemoveDisallowedAPIs(const Extension& extension,
- std::set<std::string>* apis) {
- CHECK(apis);
- std::set<std::string>::iterator i = apis->begin();
- while (i != apis->end()) {
- if (!IsFeatureAllowedForExtension(*i, extension)) {
- apis->erase(i++);
- } else {
- ++i;
- }
- }
-}
-
} // namespace
-std::set<std::string> ExtensionAPI::GetAPIsForContext(
- Feature::Context context, const Extension* extension, const GURL& url) {
- // We're forced to load all schemas now because we need to know the metadata
- // about every API -- and the metadata is stored in the schemas themselves.
- // This is a shame.
- // TODO(aa/kalman): store metadata in a separate file and don't load all
- // schemas.
- LoadAllSchemas();
-
- std::set<std::string> temp_result;
-
- // First handle all the APIs that have been converted to the feature system.
- if (extension) {
- for (APIFeatureMap::iterator iter = features_.begin();
- iter != features_.end(); ++iter) {
- if (IsAvailable(iter->first, extension, context))
- temp_result.insert(iter->first);
- }
- }
-
- // Second, fall back to the old way.
- // TODO(aa): Remove this when all APIs have been converted.
+bool ExtensionAPI::IsNonFeatureAPIAvailable(const std::string& name,
+ Feature::Context context,
+ const Extension* extension,
+ const GURL& url) {
switch (context) {
case Feature::UNSPECIFIED_CONTEXT:
break;
@@ -571,9 +556,10 @@ std::set<std::string> ExtensionAPI::GetAPIsForContext(
case Feature::BLESSED_EXTENSION_CONTEXT:
if (extension) {
// Availability is determined by the permissions of the extension.
- GetAllowedAPIs(extension, &temp_result);
- ResolveDependencies(&temp_result);
- RemoveDisallowedAPIs(*extension, &temp_result);
+ if (!IsAPIAllowed(name, extension))
+ return false;
+ if (!IsFeatureAllowedForExtension(name, *extension))
+ return false;
}
break;
@@ -582,35 +568,22 @@ std::set<std::string> ExtensionAPI::GetAPIsForContext(
if (extension) {
// Same as BLESSED_EXTENSION_CONTEXT, but only those APIs that are
// unprivileged.
- GetAllowedAPIs(extension, &temp_result);
- // Resolving dependencies before removing unprivileged APIs means that
- // some unprivileged APIs may have unrealised dependencies. Too bad!
- ResolveDependencies(&temp_result);
- RemovePrivilegedAPIs(&temp_result);
+ if (!IsAPIAllowed(name, extension))
+ return false;
+ if (!IsPrivilegedAPI(name))
+ return false;
}
break;
case Feature::WEB_PAGE_CONTEXT:
- if (url.is_valid()) {
- // Availablility is determined by the url.
- GetAPIsMatchingURL(url, &temp_result);
- }
- break;
- }
-
- // Filter out all non-API features and remove the feature type part of the
- // name.
- std::set<std::string> result;
- for (std::set<std::string>::iterator iter = temp_result.begin();
- iter != temp_result.end(); ++iter) {
- std::string feature_type;
- std::string feature_name;
- SplitDependencyName(*iter, &feature_type, &feature_name);
- if (feature_type == "api")
- result.insert(feature_name);
+ if (!url_matching_apis_.count(name))
+ return false;
+ CHECK(url.is_valid());
+ // Availablility is determined by the url.
+ return url_matching_apis_[name].MatchesURL(url);
}
- return result;
+ return true;
}
std::set<std::string> ExtensionAPI::GetAllAPINames() {
@@ -699,20 +672,10 @@ std::string ExtensionAPI::GetAPINameFromFullName(const std::string& full_name,
return "";
}
-void ExtensionAPI::GetAllowedAPIs(
- const Extension* extension, std::set<std::string>* out) {
- for (SchemaMap::const_iterator i = schemas_.begin(); i != schemas_.end();
- ++i) {
- if (features_.find(i->first) != features_.end()) {
- // This API is controlled by the feature system. Nothing to do here.
- continue;
- }
-
- if (extension->required_permission_set()->HasAnyAccessToAPI(i->first) ||
- extension->optional_permission_set()->HasAnyAccessToAPI(i->first)) {
- out->insert(i->first);
- }
- }
+bool ExtensionAPI::IsAPIAllowed(const std::string& name,
+ const Extension* extension) {
+ return extension->required_permission_set()->HasAnyAccessToAPI(name) ||
+ extension->optional_permission_set()->HasAnyAccessToAPI(name);
}
void ExtensionAPI::ResolveDependencies(std::set<std::string>* out) {
@@ -756,41 +719,9 @@ void ExtensionAPI::GetMissingDependencies(
}
}
-void ExtensionAPI::RemovePrivilegedAPIs(std::set<std::string>* apis) {
- std::set<std::string> privileged_apis;
- for (std::set<std::string>::iterator i = apis->begin(); i != apis->end();
- ++i) {
- if (!completely_unprivileged_apis_.count(*i) &&
- !partially_unprivileged_apis_.count(*i)) {
- privileged_apis.insert(*i);
- }
- }
- for (std::set<std::string>::iterator i = privileged_apis.begin();
- i != privileged_apis.end(); ++i) {
- apis->erase(*i);
- }
-}
-
-void ExtensionAPI::GetAPIsMatchingURL(const GURL& url,
- std::set<std::string>* out) {
- for (std::map<std::string, URLPatternSet>::const_iterator i =
- url_matching_apis_.begin(); i != url_matching_apis_.end(); ++i) {
- if (features_.find(i->first) != features_.end()) {
- // This API is controlled by the feature system. Nothing to do.
- continue;
- }
-
- if (i->second.MatchesURL(url))
- out->insert(i->first);
- }
-}
-
-void ExtensionAPI::LoadAllSchemas() {
- while (unloaded_schemas_.size()) {
- std::map<std::string, base::StringPiece>::iterator it =
- unloaded_schemas_.begin();
- LoadSchema(it->first, it->second);
- }
+bool ExtensionAPI::IsPrivilegedAPI(const std::string& name) {
+ return completely_unprivileged_apis_.count(name) ||
+ partially_unprivileged_apis_.count(name);
}
} // namespace extensions
« 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