| 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 f8909b053043141ea8e6ac8f67baa99436bf7231..a36989df223e8e7c9d77ebdbbe76b09a2403cfe1 100644
|
| --- a/chrome/common/extensions/api/extension_api.cc
|
| +++ b/chrome/common/extensions/api/extension_api.cc
|
| @@ -15,6 +15,7 @@
|
| #include "base/values.h"
|
| #include "chrome/common/extensions/extension.h"
|
| #include "chrome/common/extensions/extension_permission_set.h"
|
| +#include "googleurl/src/gurl.h"
|
| #include "grit/common_resources.h"
|
| #include "ui/base/resource/resource_bundle.h"
|
|
|
| @@ -22,22 +23,6 @@ namespace extensions {
|
|
|
| namespace {
|
|
|
| -// Adds any APIs listed in "dependencies" found in |schema| but not in
|
| -// |reference| to |out|.
|
| -void GetMissingDependencies(
|
| - const DictionaryValue& schema,
|
| - const ExtensionAPI::SchemaMap& reference,
|
| - std::set<std::string>* out) {
|
| - ListValue* dependencies = NULL;
|
| - if (!schema.GetList("dependencies", &dependencies))
|
| - return;
|
| - for (size_t i = 0; i < dependencies->GetSize(); ++i) {
|
| - std::string api_name;
|
| - if (dependencies->GetString(i, &api_name) && !reference.count(api_name))
|
| - out->insert(api_name);
|
| - }
|
| -}
|
| -
|
| // Returns whether the list at |name_space_node|.|child_kind| contains any
|
| // children with an { "unprivileged": true } property.
|
| bool HasUnprivilegedChild(const DictionaryValue* name_space_node,
|
| @@ -95,6 +80,7 @@ void ExtensionAPI::LoadSchemaFromResource(int resource_id) {
|
|
|
| ExtensionAPI::ExtensionAPI() {
|
| static int kJsonApiResourceIds[] = {
|
| + IDR_EXTENSION_API_JSON_APP,
|
| IDR_EXTENSION_API_JSON_BOOKMARKS,
|
| IDR_EXTENSION_API_JSON_BROWSERACTION,
|
| IDR_EXTENSION_API_JSON_BROWSING_DATA,
|
| @@ -179,6 +165,27 @@ ExtensionAPI::ExtensionAPI() {
|
| partially_unprivileged_apis_.insert(it->first);
|
| }
|
| }
|
| +
|
| + // Populate |url_matching_apis_|.
|
| + for (SchemaMap::const_iterator it = schemas_.begin();
|
| + it != schemas_.end(); ++it) {
|
| + ListValue* matches = NULL;
|
| + {
|
| + Value* matches_value = NULL;
|
| + if (!it->second->Get("matches", &matches_value))
|
| + continue;
|
| + CHECK_EQ(Value::TYPE_LIST, matches_value->GetType());
|
| + matches = static_cast<ListValue*>(matches_value);
|
| + }
|
| + 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::kValidUserScriptSchemes, pattern));
|
| + }
|
| + url_matching_apis_[it->first] = pattern_set;
|
| + }
|
| }
|
|
|
| ExtensionAPI::~ExtensionAPI() {
|
| @@ -258,59 +265,108 @@ const base::DictionaryValue* ExtensionAPI::GetSchema(
|
| return maybe_schema != schemas_.end() ? maybe_schema->second.get() : NULL;
|
| }
|
|
|
| -void ExtensionAPI::GetSchemasForExtension(const Extension& extension,
|
| - GetSchemasFilter filter,
|
| - SchemaMap* out) const {
|
| - // Check both required_permissions and optional_permissions since we need
|
| - // to return all schemas that might be needed.
|
| - GetSchemasForPermissions(*extension.required_permission_set(), filter, out);
|
| - GetSchemasForPermissions(*extension.optional_permission_set(), filter, out);
|
| -
|
| - // Note that dependency resolution might introduce APIs outside of the filter
|
| - // (for example, "extensions" has unprivileged componenents but relies on
|
| - // "tabs" which doesn't). It doesn't matter because schema_generated_bindings
|
| - // does individual function/event based checking anyway, but it's a shame.
|
| - ResolveDependencies(out);
|
| +scoped_ptr<std::set<std::string> > ExtensionAPI::GetAPIsForContext(
|
| + Feature::Context context,
|
| + const Extension* extension,
|
| + const GURL& url) const {
|
| + scoped_ptr<std::set<std::string> > result(new std::set<std::string>());
|
| +
|
| + switch (context) {
|
| + case Feature::UNSPECIFIED_CONTEXT:
|
| + break;
|
| +
|
| + case Feature::PRIVILEGED_CONTEXT:
|
| + // Availability is determined by the permissions of the extension.
|
| + CHECK(extension);
|
| + GetAllowedAPIs(extension, result.get());
|
| + ResolveDependencies(result.get());
|
| + break;
|
| +
|
| + case Feature::UNPRIVILEGED_CONTEXT:
|
| + case Feature::CONTENT_SCRIPT_CONTEXT:
|
| + // Same as PRIVILEGED_CONTEXT, but only those APIs that are unprivileged.
|
| + CHECK(extension);
|
| + GetAllowedAPIs(extension, result.get());
|
| + // Resolving dependencies before removing unprivileged APIs means that
|
| + // some unprivileged APIs may have unrealised dependencies. Too bad!
|
| + ResolveDependencies(result.get());
|
| + RemovePrivilegedAPIs(result.get());
|
| + break;
|
| +
|
| + case Feature::WEB_PAGE_CONTEXT:
|
| + // Availablility is determined by the url.
|
| + CHECK(url.is_valid());
|
| + GetAPIsMatchingURL(url, result.get());
|
| + break;
|
| + }
|
| +
|
| + return result.Pass();
|
| +}
|
| +
|
| +void ExtensionAPI::GetAllowedAPIs(
|
| + const Extension* extension, std::set<std::string>* out) const {
|
| + for (SchemaMap::const_iterator i = schemas_.begin(); i != schemas_.end();
|
| + ++i) {
|
| + if (extension->required_permission_set()->HasAnyAccessToAPI(i->first) ||
|
| + extension->optional_permission_set()->HasAnyAccessToAPI(i->first)) {
|
| + out->insert(i->first);
|
| + }
|
| + }
|
| }
|
|
|
| -void ExtensionAPI::ResolveDependencies(SchemaMap* out) const {
|
| +void ExtensionAPI::ResolveDependencies(std::set<std::string>* out) const {
|
| std::set<std::string> missing_dependencies;
|
| - for (SchemaMap::const_iterator i = out->begin(); i != out->end(); ++i)
|
| - GetMissingDependencies(*i->second, *out, &missing_dependencies);
|
| + for (std::set<std::string>::iterator i = out->begin(); i != out->end(); ++i)
|
| + GetMissingDependencies(*i, *out, &missing_dependencies);
|
|
|
| while (missing_dependencies.size()) {
|
| - std::string api_name = *missing_dependencies.begin();
|
| - missing_dependencies.erase(api_name);
|
| - linked_ptr<const DictionaryValue> schema = schemas_.find(api_name)->second;
|
| - (*out)[api_name] = schema;
|
| - GetMissingDependencies(*schema, *out, &missing_dependencies);
|
| + std::string next = *missing_dependencies.begin();
|
| + missing_dependencies.erase(next);
|
| + out->insert(next);
|
| + GetMissingDependencies(next, *out, &missing_dependencies);
|
| }
|
| }
|
|
|
| -void ExtensionAPI::GetDefaultSchemas(GetSchemasFilter filter,
|
| - SchemaMap* out) const {
|
| - scoped_refptr<ExtensionPermissionSet> default_permissions(
|
| - new ExtensionPermissionSet());
|
| - GetSchemasForPermissions(*default_permissions, filter, out);
|
| - ResolveDependencies(out);
|
| +void ExtensionAPI::GetMissingDependencies(
|
| + const std::string& api_name,
|
| + const std::set<std::string>& excluding,
|
| + std::set<std::string>* out) const {
|
| + const base::DictionaryValue* schema = GetSchema(api_name);
|
| + CHECK(schema) << "Schema for " << api_name << " not found";
|
| +
|
| + ListValue* dependencies = NULL;
|
| + if (!schema->GetList("dependencies", &dependencies))
|
| + return;
|
| +
|
| + for (size_t i = 0; i < dependencies->GetSize(); ++i) {
|
| + std::string api_name;
|
| + if (dependencies->GetString(i, &api_name) && !excluding.count(api_name))
|
| + out->insert(api_name);
|
| + }
|
| }
|
|
|
| -void ExtensionAPI::GetSchemasForPermissions(
|
| - const ExtensionPermissionSet& permissions,
|
| - GetSchemasFilter filter,
|
| - SchemaMap* out) const {
|
| - for (SchemaMap::const_iterator it = schemas_.begin(); it != schemas_.end();
|
| - ++it) {
|
| - if (filter == ONLY_UNPRIVILEGED && IsWholeAPIPrivileged(it->first))
|
| - continue;
|
| - if (permissions.HasAnyAccessToAPI(it->first))
|
| - (*out)[it->first] = it->second;
|
| +void ExtensionAPI::RemovePrivilegedAPIs(std::set<std::string>* apis) const {
|
| + 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);
|
| }
|
| }
|
|
|
| -bool ExtensionAPI::IsWholeAPIPrivileged(const std::string& api_name) const {
|
| - return !completely_unprivileged_apis_.count(api_name) &&
|
| - !partially_unprivileged_apis_.count(api_name);
|
| +void ExtensionAPI::GetAPIsMatchingURL(const GURL& url,
|
| + std::set<std::string>* out) const {
|
| + for (std::map<std::string, URLPatternSet>::const_iterator i =
|
| + url_matching_apis_.begin(); i != url_matching_apis_.end(); ++i) {
|
| + if (i->second.MatchesURL(url))
|
| + out->insert(i->first);
|
| + }
|
| }
|
|
|
| } // namespace extensions
|
|
|