summaryrefslogtreecommitdiffstats
path: root/chrome/common/extensions
diff options
context:
space:
mode:
authorpfeldman@chromium.org <pfeldman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-23 10:02:15 +0000
committerpfeldman@chromium.org <pfeldman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-23 10:02:15 +0000
commit096bf9b475c2d59341fb427398a8b5ab0cfb0005 (patch)
tree366ce94d1810783c4990fe826c11a3e527677895 /chrome/common/extensions
parentcc7dd06075650443b0fe42609e6fd6855caf6764 (diff)
downloadchromium_src-096bf9b475c2d59341fb427398a8b5ab0cfb0005.zip
chromium_src-096bf9b475c2d59341fb427398a8b5ab0cfb0005.tar.gz
chromium_src-096bf9b475c2d59341fb427398a8b5ab0cfb0005.tar.bz2
Revert r128434 "Make ExtensionAPI load schemas lazily where possible." for breaking install tests.
TBR=kalman Review URL: https://chromiumcodereview.appspot.com/9845007 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@128448 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/common/extensions')
-rw-r--r--chrome/common/extensions/api/extension_api.cc380
-rw-r--r--chrome/common/extensions/api/extension_api.h46
-rw-r--r--chrome/common/extensions/api/extension_api_unittest.cc104
3 files changed, 211 insertions, 319 deletions
diff --git a/chrome/common/extensions/api/extension_api.cc b/chrome/common/extensions/api/extension_api.cc
index d6612d9..91b785b 100644
--- a/chrome/common/extensions/api/extension_api.cc
+++ b/chrome/common/extensions/api/extension_api.cc
@@ -20,14 +20,8 @@
#include "grit/common_resources.h"
#include "ui/base/resource/resource_bundle.h"
-using base::DictionaryValue;
-using base::ListValue;
-using base::Value;
-
namespace extensions {
-using api::GeneratedSchemas;
-
namespace {
// Returns whether the list at |name_space_node|.|child_kind| contains any
@@ -50,213 +44,163 @@ bool HasUnprivilegedChild(const DictionaryValue* name_space_node,
return false;
}
-base::StringPiece ReadFromResource(int resource_id) {
- return ResourceBundle::GetSharedInstance().GetRawDataResource(resource_id);
+} // namespace
+
+// static
+ExtensionAPI* ExtensionAPI::GetInstance() {
+ return Singleton<ExtensionAPI>::get();
}
-scoped_ptr<ListValue> LoadSchemaList(const base::StringPiece& schema) {
+static base::ListValue* LoadSchemaList(int resource_id) {
+ const bool kAllowTrailingCommas = false;
std::string error_message;
- scoped_ptr<Value> result(
+ Value* result =
base::JSONReader::ReadAndReturnError(
- schema.as_string(),
- false, // allow trailing commas
+ ResourceBundle::GetSharedInstance().GetRawDataResource(
+ resource_id).as_string(),
+ kAllowTrailingCommas,
NULL, // error code
- &error_message));
- CHECK(result.get()) << error_message;
- CHECK(result->IsType(Value::TYPE_LIST));
- return scoped_ptr<ListValue>(static_cast<ListValue*>(result.release()));
+ &error_message);
+ CHECK(result) << error_message;
+ CHECK(result->IsType(base::Value::TYPE_LIST));
+ return static_cast<base::ListValue*>(result);
}
-} // namespace
-
-// static
-ExtensionAPI* ExtensionAPI::GetInstance() {
- return Singleton<ExtensionAPI>::get();
+void ExtensionAPI::LoadSchemaFromResource(int resource_id) {
+ RegisterSchema(LoadSchemaList(resource_id));
}
-void ExtensionAPI::LoadSchema(const base::StringPiece& schema) {
- scoped_ptr<ListValue> schema_list(LoadSchemaList(schema));
+void ExtensionAPI::RegisterSchema(base::ListValue* loaded_schema) {
+ // We take ownership of loaded_schema, so we need to delete it.
+ scoped_ptr<base::ListValue> scoped_loaded_schema(loaded_schema);
+ Value* value = NULL;
std::string schema_namespace;
+ while (!loaded_schema->empty()) {
+ loaded_schema->Remove(loaded_schema->GetSize() - 1, &value);
+ CHECK(value->IsType(Value::TYPE_DICTIONARY));
+ const DictionaryValue* schema = static_cast<const DictionaryValue*>(value);
+ CHECK(schema->GetString("namespace", &schema_namespace));
+ schemas_[schema_namespace] = linked_ptr<const DictionaryValue>(schema);
+ }
+}
- while (!schema_list->empty()) {
- const DictionaryValue* schema = NULL;
- {
- Value* value = NULL;
- schema_list->Remove(schema_list->GetSize() - 1, &value);
- CHECK(value->IsType(Value::TYPE_DICTIONARY));
- schema = static_cast<const DictionaryValue*>(value);
+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,
+ IDR_EXTENSION_API_JSON_CHROMEAUTHPRIVATE,
+ IDR_EXTENSION_API_JSON_CHROMEOSINFOPRIVATE,
+ IDR_EXTENSION_API_JSON_CHROMEPRIVATE,
+ IDR_EXTENSION_API_JSON_CONTENTSETTINGS,
+ IDR_EXTENSION_API_JSON_CONTEXTMENUS,
+ IDR_EXTENSION_API_JSON_COOKIES,
+ IDR_EXTENSION_API_JSON_DEBUGGER,
+ IDR_EXTENSION_API_JSON_DEVTOOLS,
+ IDR_EXTENSION_API_JSON_EXPERIMENTAL_ACCESSIBILITY,
+ IDR_EXTENSION_API_JSON_EXPERIMENTAL_APP,
+ IDR_EXTENSION_API_JSON_EXPERIMENTAL_BOOKMARKMANAGER,
+ IDR_EXTENSION_API_JSON_EXPERIMENTAL_DECLARATIVE,
+ IDR_EXTENSION_API_JSON_EXPERIMENTAL_DOWNLOADS,
+ IDR_EXTENSION_API_JSON_EXPERIMENTAL_EXTENSIONS,
+ IDR_EXTENSION_API_JSON_EXPERIMENTAL_FONTS,
+ IDR_EXTENSION_API_JSON_EXPERIMENTAL_INFOBARS,
+ IDR_EXTENSION_API_JSON_EXPERIMENTAL_INPUT_UI,
+ IDR_EXTENSION_API_JSON_EXPERIMENTAL_INPUT_VIRTUALKEYBOARD,
+ IDR_EXTENSION_API_JSON_EXPERIMENTAL_KEYBINDING,
+ IDR_EXTENSION_API_JSON_EXPERIMENTAL_MANAGED_MODE,
+ IDR_EXTENSION_API_JSON_EXPERIMENTAL_OFFSCREENTABS,
+ IDR_EXTENSION_API_JSON_EXPERIMENTAL_PROCESSES,
+ IDR_EXTENSION_API_JSON_EXPERIMENTAL_RLZ,
+ IDR_EXTENSION_API_JSON_EXPERIMENTAL_SERIAL,
+ IDR_EXTENSION_API_JSON_EXPERIMENTAL_SOCKET,
+ IDR_EXTENSION_API_JSON_EXPERIMENTAL_SPEECHINPUT,
+ IDR_EXTENSION_API_JSON_EXPERIMENTAL_WEBREQUEST,
+ IDR_EXTENSION_API_JSON_EXTENSION,
+ IDR_EXTENSION_API_JSON_FILEBROWSERHANDLER,
+ IDR_EXTENSION_API_JSON_FILEBROWSERPRIVATE,
+ IDR_EXTENSION_API_JSON_HISTORY,
+ IDR_EXTENSION_API_JSON_I18N,
+ IDR_EXTENSION_API_JSON_IDLE,
+ IDR_EXTENSION_API_JSON_INPUT_IME,
+ IDR_EXTENSION_API_JSON_INPUTMETHODPRIVATE,
+ IDR_EXTENSION_API_JSON_MANAGEMENT,
+ IDR_EXTENSION_API_JSON_MEDIAPLAYERPRIVATE,
+ IDR_EXTENSION_API_JSON_METRICSPRIVATE,
+ IDR_EXTENSION_API_JSON_OFFERSPRIVATE,
+ IDR_EXTENSION_API_JSON_OMNIBOX,
+ IDR_EXTENSION_API_JSON_PAGEACTION,
+ IDR_EXTENSION_API_JSON_PAGEACTIONS,
+ IDR_EXTENSION_API_JSON_PAGECAPTURE,
+ IDR_EXTENSION_API_JSON_PERMISSIONS,
+ IDR_EXTENSION_API_JSON_PRIVACY,
+ IDR_EXTENSION_API_JSON_PROXY,
+ IDR_EXTENSION_API_JSON_STORAGE,
+ IDR_EXTENSION_API_JSON_SYSTEMPRIVATE,
+ IDR_EXTENSION_API_JSON_TABS,
+ IDR_EXTENSION_API_JSON_TERMINALPRIVATE,
+ IDR_EXTENSION_API_JSON_TEST,
+ IDR_EXTENSION_API_JSON_TOPSITES,
+ IDR_EXTENSION_API_JSON_TTS,
+ IDR_EXTENSION_API_JSON_TTSENGINE,
+ IDR_EXTENSION_API_JSON_TYPES,
+ IDR_EXTENSION_API_JSON_WEBNAVIGATION,
+ IDR_EXTENSION_API_JSON_WEBREQUEST,
+ IDR_EXTENSION_API_JSON_WEBSOCKETPROXYPRIVATE,
+ IDR_EXTENSION_API_JSON_WEBSTORE,
+ IDR_EXTENSION_API_JSON_WEBSTOREPRIVATE,
+ IDR_EXTENSION_API_JSON_WINDOWS,
+ };
+
+ for (size_t i = 0; i < arraysize(kJsonApiResourceIds); i++) {
+ LoadSchemaFromResource(kJsonApiResourceIds[i]);
+ }
+ RegisterSchema(api::GeneratedSchemas::Get());
+
+ // Populate {completely,partially}_unprivileged_apis_.
+ for (SchemaMap::iterator it = schemas_.begin(); it != schemas_.end(); ++it) {
+ bool unprivileged = false;
+ it->second->GetBoolean("unprivileged", &unprivileged);
+ if (unprivileged) {
+ completely_unprivileged_apis_.insert(it->first);
+ continue;
}
- CHECK(schema->GetString("namespace", &schema_namespace));
- schemas_[schema_namespace] = make_linked_ptr(schema);
- 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.
- if (schema->HasKey("unprivileged")) {
- completely_unprivileged_apis_.insert(schema_namespace);
- } else if (HasUnprivilegedChild(schema, "functions") ||
- HasUnprivilegedChild(schema, "events")) {
- partially_unprivileged_apis_.insert(schema_namespace);
+ // Only need to look at functions/events; even though there are unprivileged
+ // properties (e.g. in extensions), access to those never reaches C++ land.
+ if (HasUnprivilegedChild(it->second.get(), "functions") ||
+ HasUnprivilegedChild(it->second.get(), "events")) {
+ partially_unprivileged_apis_.insert(it->first);
}
+ }
- // Populate |url_matching_apis_|.
+ // Populate |url_matching_apis_|.
+ for (SchemaMap::const_iterator it = schemas_.begin();
+ it != schemas_.end(); ++it) {
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::kValidUserScriptSchemes, pattern));
- }
- url_matching_apis_[schema_namespace] = pattern_set;
+ {
+ 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() {
- // Schemas to be loaded from resources.
- unloaded_schemas_["app"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_APP);
- unloaded_schemas_["bookmarks"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_BOOKMARKS);
- unloaded_schemas_["browserAction"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_BROWSERACTION);
- unloaded_schemas_["browsingData"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_BROWSINGDATA);
- unloaded_schemas_["chromeAuthPrivate"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_CHROMEAUTHPRIVATE);
- unloaded_schemas_["chromeosInfoPrivate"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_CHROMEOSINFOPRIVATE);
- unloaded_schemas_["chromePrivate"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_CHROMEPRIVATE);
- unloaded_schemas_["contentSettings"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_CONTENTSETTINGS);
- unloaded_schemas_["contextMenus"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_CONTEXTMENUS);
- unloaded_schemas_["cookies"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_COOKIES);
- unloaded_schemas_["debugger"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_DEBUGGER);
- unloaded_schemas_["devtools"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_DEVTOOLS);
- unloaded_schemas_["experimental.accessibility"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_EXPERIMENTAL_ACCESSIBILITY);
- unloaded_schemas_["experimental.app"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_EXPERIMENTAL_APP);
- unloaded_schemas_["experimental.bookmarkManager"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_EXPERIMENTAL_BOOKMARKMANAGER);
- unloaded_schemas_["experimental.declarative"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_EXPERIMENTAL_DECLARATIVE);
- unloaded_schemas_["experimental.downloads"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_EXPERIMENTAL_DOWNLOADS);
- unloaded_schemas_["experimental.extension"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_EXPERIMENTAL_EXTENSION);
- unloaded_schemas_["experimental.fontSettings"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_EXPERIMENTAL_FONTSSETTINGS);
- unloaded_schemas_["experimental.infobars"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_EXPERIMENTAL_INFOBARS);
- unloaded_schemas_["experimental.input.ui"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_EXPERIMENTAL_INPUT_UI);
- unloaded_schemas_["experimental.input.virtualKeyboard"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_EXPERIMENTAL_INPUT_VIRTUALKEYBOARD);
- unloaded_schemas_["experimental.keybinding"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_EXPERIMENTAL_KEYBINDING);
- unloaded_schemas_["experimental.managedMode"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_EXPERIMENTAL_MANAGEDMODE);
- unloaded_schemas_["experimental.offscreenTabs"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_EXPERIMENTAL_OFFSCREENTABS);
- unloaded_schemas_["experimental.processes"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_EXPERIMENTAL_PROCESSES);
- unloaded_schemas_["experimental.rlz"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_EXPERIMENTAL_RLZ);
- unloaded_schemas_["experimental.serial"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_EXPERIMENTAL_SERIAL);
- unloaded_schemas_["experimental.socket"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_EXPERIMENTAL_SOCKET);
- unloaded_schemas_["experimental.speechInput"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_EXPERIMENTAL_SPEECHINPUT);
- unloaded_schemas_["experimental.webRequest"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_EXPERIMENTAL_WEBREQUEST);
- unloaded_schemas_["extension"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_EXTENSION);
- unloaded_schemas_["fileBrowserHandler"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_FILEBROWSERHANDLER);
- unloaded_schemas_["fileBrowserPrivate"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_FILEBROWSERPRIVATE);
- unloaded_schemas_["history"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_HISTORY);
- unloaded_schemas_["i18n"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_I18N);
- unloaded_schemas_["idle"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_IDLE);
- unloaded_schemas_["input.ime"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_INPUT_IME);
- unloaded_schemas_["inputMethodPrivate"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_INPUTMETHODPRIVATE);
- unloaded_schemas_["management"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_MANAGEMENT);
- unloaded_schemas_["mediaPlayerPrivate"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_MEDIAPLAYERPRIVATE);
- unloaded_schemas_["metricsPrivate"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_METRICSPRIVATE);
- unloaded_schemas_["offersPrivate"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_OFFERSPRIVATE);
- unloaded_schemas_["omnibox"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_OMNIBOX);
- unloaded_schemas_["pageAction"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_PAGEACTION);
- unloaded_schemas_["pageActions"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_PAGEACTIONS);
- unloaded_schemas_["pageCapture"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_PAGECAPTURE);
- unloaded_schemas_["permissions"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_PERMISSIONS);
- unloaded_schemas_["privacy"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_PRIVACY);
- unloaded_schemas_["proxy"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_PROXY);
- unloaded_schemas_["storage"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_STORAGE);
- unloaded_schemas_["systemPrivate"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_SYSTEMPRIVATE);
- unloaded_schemas_["tabs"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_TABS);
- unloaded_schemas_["terminalPrivate"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_TERMINALPRIVATE);
- unloaded_schemas_["test"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_TEST);
- unloaded_schemas_["topSites"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_TOPSITES);
- unloaded_schemas_["ttsEngine"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_TTSENGINE);
- unloaded_schemas_["tts"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_TTS);
- unloaded_schemas_["types"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_TYPES);
- unloaded_schemas_["webNavigation"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_WEBNAVIGATION);
- unloaded_schemas_["webRequest"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_WEBREQUEST);
- unloaded_schemas_["webSocketProxyPrivate"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_WEBSOCKETPROXYPRIVATE);
- unloaded_schemas_["webstorePrivate"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_WEBSTOREPRIVATE);
- unloaded_schemas_["windows"] = ReadFromResource(
- IDR_EXTENSION_API_JSON_WINDOWS);
-
- // Schemas to be loaded via JSON generated from IDL files.
- GeneratedSchemas::Get(&unloaded_schemas_);
-}
-
ExtensionAPI::~ExtensionAPI() {
}
-bool ExtensionAPI::IsPrivileged(const std::string& full_name) {
+bool ExtensionAPI::IsPrivileged(const std::string& full_name) const {
std::string api_name;
std::string child_name;
@@ -280,13 +224,11 @@ bool ExtensionAPI::IsPrivileged(const std::string& full_name) {
child_name = split[0];
}
- // GetSchema to ensure that it gets loaded before any checks.
- const DictionaryValue* schema = GetSchema(api_name);
-
if (completely_unprivileged_apis_.count(api_name))
return false;
if (partially_unprivileged_apis_.count(api_name)) {
+ const DictionaryValue* schema = GetSchema(api_name);
return IsChildNamePrivileged(schema, "functions", child_name) &&
IsChildNamePrivileged(schema, "events", child_name);
}
@@ -295,9 +237,9 @@ bool ExtensionAPI::IsPrivileged(const std::string& full_name) {
}
DictionaryValue* ExtensionAPI::FindListItem(
- const ListValue* list,
+ const base::ListValue* list,
const std::string& property_name,
- const std::string& property_value) {
+ const std::string& property_value) const {
for (size_t i = 0; i < list->GetSize(); ++i) {
DictionaryValue* item = NULL;
CHECK(list->GetDictionary(i, &item))
@@ -312,7 +254,7 @@ DictionaryValue* ExtensionAPI::FindListItem(
bool ExtensionAPI::IsChildNamePrivileged(const DictionaryValue* name_space_node,
const std::string& child_kind,
- const std::string& child_name) {
+ const std::string& child_name) const {
ListValue* child_list = NULL;
name_space_node->GetList(child_kind, &child_list);
if (!child_list)
@@ -326,32 +268,16 @@ bool ExtensionAPI::IsChildNamePrivileged(const DictionaryValue* name_space_node,
return !unprivileged;
}
-const DictionaryValue* ExtensionAPI::GetSchema(const std::string& api_name) {
+const base::DictionaryValue* ExtensionAPI::GetSchema(
+ const std::string& api_name) const {
SchemaMap::const_iterator maybe_schema = schemas_.find(api_name);
- if (maybe_schema != schemas_.end())
- return maybe_schema->second.get();
-
- // Might not have loaded yet; or might just not exist.
- std::map<std::string, base::StringPiece>::iterator maybe_schema_resource =
- unloaded_schemas_.find(api_name);
- if (maybe_schema_resource == unloaded_schemas_.end())
- return NULL;
-
- LoadSchema(maybe_schema_resource->second);
- maybe_schema = schemas_.find(api_name);
- CHECK(schemas_.end() != maybe_schema);
- return maybe_schema->second.get();
+ return maybe_schema != schemas_.end() ? maybe_schema->second.get() : NULL;
}
scoped_ptr<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();
-
+ Feature::Context context,
+ const Extension* extension,
+ const GURL& url) const {
scoped_ptr<std::set<std::string> > result(new std::set<std::string>());
switch (context) {
@@ -388,7 +314,7 @@ scoped_ptr<std::set<std::string> > ExtensionAPI::GetAPIsForContext(
}
void ExtensionAPI::GetAllowedAPIs(
- const Extension* extension, std::set<std::string>* out) {
+ 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) ||
@@ -398,7 +324,7 @@ void ExtensionAPI::GetAllowedAPIs(
}
}
-void ExtensionAPI::ResolveDependencies(std::set<std::string>* out) {
+void ExtensionAPI::ResolveDependencies(std::set<std::string>* out) const {
std::set<std::string> missing_dependencies;
for (std::set<std::string>::iterator i = out->begin(); i != out->end(); ++i)
GetMissingDependencies(*i, *out, &missing_dependencies);
@@ -414,8 +340,8 @@ void ExtensionAPI::ResolveDependencies(std::set<std::string>* out) {
void ExtensionAPI::GetMissingDependencies(
const std::string& api_name,
const std::set<std::string>& excluding,
- std::set<std::string>* out) {
- const DictionaryValue* schema = GetSchema(api_name);
+ std::set<std::string>* out) const {
+ const base::DictionaryValue* schema = GetSchema(api_name);
CHECK(schema) << "Schema for " << api_name << " not found";
ListValue* dependencies = NULL;
@@ -429,7 +355,7 @@ void ExtensionAPI::GetMissingDependencies(
}
}
-void ExtensionAPI::RemovePrivilegedAPIs(std::set<std::string>* apis) {
+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) {
@@ -445,7 +371,7 @@ void ExtensionAPI::RemovePrivilegedAPIs(std::set<std::string>* apis) {
}
void ExtensionAPI::GetAPIsMatchingURL(const GURL& url,
- std::set<std::string>* out) {
+ 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))
@@ -453,10 +379,4 @@ void ExtensionAPI::GetAPIsMatchingURL(const GURL& url,
}
}
-void ExtensionAPI::LoadAllSchemas() {
- while (unloaded_schemas_.size()) {
- LoadSchema(unloaded_schemas_.begin()->second);
- }
-}
-
} // namespace extensions
diff --git a/chrome/common/extensions/api/extension_api.h b/chrome/common/extensions/api/extension_api.h
index 1ae7824..4907152 100644
--- a/chrome/common/extensions/api/extension_api.h
+++ b/chrome/common/extensions/api/extension_api.h
@@ -14,7 +14,6 @@
#include "base/memory/linked_ptr.h"
#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
-#include "base/string_piece.h"
#include "base/values.h"
#include "chrome/common/extensions/feature.h"
#include "chrome/common/extensions/url_pattern_set.h"
@@ -37,77 +36,76 @@ class ExtensionAPI {
// Returns the single instance of this class.
static ExtensionAPI* GetInstance();
- // Public for construction from unit tests. Use GetInstance() normally.
- ExtensionAPI();
- ~ExtensionAPI();
-
// Returns true if |name| is a privileged API path. Privileged paths can only
// be called from extension code which is running in its own designated
// extension process. They cannot be called from extension code running in
// content scripts, or other low-privileged contexts.
- bool IsPrivileged(const std::string& name);
+ bool IsPrivileged(const std::string& name) const;
// Gets the schema for the extension API with namespace |api_name|.
// Ownership remains with this object.
- const base::DictionaryValue* GetSchema(const std::string& api_name);
+ const base::DictionaryValue* GetSchema(const std::string& api_name) const;
// Gets the APIs available to |context| given an |extension| and |url|. The
// extension or URL may not be relevant to all contexts, and may be left
// NULL/empty.
scoped_ptr<std::set<std::string> > GetAPIsForContext(
- Feature::Context context, const Extension* extension, const GURL& url);
+ Feature::Context context,
+ const Extension* extension,
+ const GURL& url) const;
private:
friend struct DefaultSingletonTraits<ExtensionAPI>;
- // Loads a schema.
- void LoadSchema(const base::StringPiece& schema);
+ ExtensionAPI();
+ ~ExtensionAPI();
+
+ // Loads a schema from a resource.
+ void LoadSchemaFromResource(int resource_id);
+
+ // Given a schema in ListValue form, registers it in a map. Takes ownership
+ // of |loaded_schema|.
+ void RegisterSchema(base::ListValue* loaded_schema);
// Find an item in |list| with the specified property name and value, or NULL
// if no such item exists.
base::DictionaryValue* FindListItem(const base::ListValue* list,
const std::string& property_name,
- const std::string& property_value);
+ const std::string& property_value) const;
// Returns true if the function or event under |namespace_node| with
// the specified |child_name| is privileged, or false otherwise. If the name
// is not found, defaults to privileged.
bool IsChildNamePrivileged(const base::DictionaryValue* namespace_node,
const std::string& child_kind,
- const std::string& child_name);
+ const std::string& child_name) const;
// Adds all APIs to |out| that |extension| has any permission (required or
// optional) to use.
- void GetAllowedAPIs(const Extension* extension, std::set<std::string>* out);
+ void GetAllowedAPIs(
+ const Extension* extension, std::set<std::string>* out) const;
// Adds dependent schemas to |out| as determined by the "dependencies"
// property.
- void ResolveDependencies(std::set<std::string>* out);
+ void ResolveDependencies(std::set<std::string>* out) const;
// Adds any APIs listed in "dependencies" found in the schema for |api_name|
// but not in |excluding| to |out|.
void GetMissingDependencies(
const std::string& api_name,
const std::set<std::string>& excluding,
- std::set<std::string>* out);
+ std::set<std::string>* out) const;
// Removes all APIs from |apis| which are *entirely* privileged. This won't
// include APIs such as "storage" which is entirely unprivileged, nor
// "extension" which has unprivileged components.
- void RemovePrivilegedAPIs(std::set<std::string>* apis);
+ void RemovePrivilegedAPIs(std::set<std::string>* apis) const;
// Adds an APIs that match |url| to |out|.
- void GetAPIsMatchingURL(const GURL& url, std::set<std::string>* out);
-
- // Loads all remaining resources from |unloaded_schemas_|.
- void LoadAllSchemas();
+ void GetAPIsMatchingURL(const GURL& url, std::set<std::string>* out) const;
static ExtensionAPI* instance_;
- // Map from each API that hasn't been loaded yet to the schema which defines
- // it. Note that there may be multiple APIs per schema.
- std::map<std::string, base::StringPiece> unloaded_schemas_;
-
// Schemas for each namespace.
typedef std::map<std::string, linked_ptr<const DictionaryValue> > SchemaMap;
SchemaMap schemas_;
diff --git a/chrome/common/extensions/api/extension_api_unittest.cc b/chrome/common/extensions/api/extension_api_unittest.cc
index d6e324f..1bcf33b 100644
--- a/chrome/common/extensions/api/extension_api_unittest.cc
+++ b/chrome/common/extensions/api/extension_api_unittest.cc
@@ -13,57 +13,36 @@
#include "chrome/common/extensions/extension.h"
#include "testing/gtest/include/gtest/gtest.h"
-namespace extensions {
namespace {
-TEST(ExtensionAPI, IsPrivileged) {
- ExtensionAPI extension_api;
+using extensions::ExtensionAPI;
+using extensions::Feature;
- EXPECT_FALSE(extension_api.IsPrivileged("extension.connect"));
- EXPECT_FALSE(extension_api.IsPrivileged("extension.onConnect"));
+TEST(ExtensionAPI, IsPrivileged) {
+ ExtensionAPI* extension_api = ExtensionAPI::GetInstance();
+ EXPECT_FALSE(extension_api->IsPrivileged("extension.connect"));
+ EXPECT_FALSE(extension_api->IsPrivileged("extension.onConnect"));
// Properties are not supported yet.
- EXPECT_TRUE(extension_api.IsPrivileged("extension.lastError"));
+ EXPECT_TRUE(extension_api->IsPrivileged("extension.lastError"));
// Default unknown names to privileged for paranoia's sake.
- EXPECT_TRUE(extension_api.IsPrivileged(""));
- EXPECT_TRUE(extension_api.IsPrivileged("<unknown-namespace>"));
- EXPECT_TRUE(extension_api.IsPrivileged("extension.<unknown-member>"));
+ EXPECT_TRUE(extension_api->IsPrivileged(""));
+ EXPECT_TRUE(extension_api->IsPrivileged("<unknown-namespace>"));
+ EXPECT_TRUE(extension_api->IsPrivileged("extension.<unknown-member>"));
// Exists, but privileged.
- EXPECT_TRUE(extension_api.IsPrivileged("extension.getViews"));
- EXPECT_TRUE(extension_api.IsPrivileged("history.search"));
+ EXPECT_TRUE(extension_api->IsPrivileged("extension.getViews"));
+ EXPECT_TRUE(extension_api->IsPrivileged("history.search"));
// Whole APIs that are unprivileged.
- EXPECT_FALSE(extension_api.IsPrivileged("app.getDetails"));
- EXPECT_FALSE(extension_api.IsPrivileged("app.isInstalled"));
- EXPECT_FALSE(extension_api.IsPrivileged("storage.local"));
- EXPECT_FALSE(extension_api.IsPrivileged("storage.local.onChanged"));
- EXPECT_FALSE(extension_api.IsPrivileged("storage.local.set"));
- EXPECT_FALSE(extension_api.IsPrivileged("storage.local.MAX_ITEMS"));
- EXPECT_FALSE(extension_api.IsPrivileged("storage.set"));
-}
-
-TEST(ExtensionAPI, LazyGetSchema) {
- ExtensionAPI apis;
-
- EXPECT_EQ(NULL, apis.GetSchema(""));
- EXPECT_EQ(NULL, apis.GetSchema(""));
- EXPECT_EQ(NULL, apis.GetSchema("experimental"));
- EXPECT_EQ(NULL, apis.GetSchema("experimental"));
- EXPECT_EQ(NULL, apis.GetSchema("foo"));
- EXPECT_EQ(NULL, apis.GetSchema("foo"));
-
- EXPECT_TRUE(apis.GetSchema("experimental.dns"));
- EXPECT_TRUE(apis.GetSchema("experimental.dns"));
- EXPECT_TRUE(apis.GetSchema("experimental.infobars"));
- EXPECT_TRUE(apis.GetSchema("experimental.infobars"));
- EXPECT_TRUE(apis.GetSchema("extension"));
- EXPECT_TRUE(apis.GetSchema("extension"));
- EXPECT_TRUE(apis.GetSchema("omnibox"));
- EXPECT_TRUE(apis.GetSchema("omnibox"));
- EXPECT_TRUE(apis.GetSchema("storage"));
- EXPECT_TRUE(apis.GetSchema("storage"));
+ EXPECT_FALSE(extension_api->IsPrivileged("app.getDetails"));
+ EXPECT_FALSE(extension_api->IsPrivileged("app.isInstalled"));
+ EXPECT_FALSE(extension_api->IsPrivileged("storage.local"));
+ EXPECT_FALSE(extension_api->IsPrivileged("storage.local.onChanged"));
+ EXPECT_FALSE(extension_api->IsPrivileged("storage.local.set"));
+ EXPECT_FALSE(extension_api->IsPrivileged("storage.local.MAX_ITEMS"));
+ EXPECT_FALSE(extension_api->IsPrivileged("storage.set"));
}
scoped_refptr<Extension> CreateExtensionWithPermissions(
@@ -105,18 +84,16 @@ TEST(ExtensionAPI, ExtensionWithUnprivilegedAPIs) {
extension = CreateExtensionWithPermissions(permissions);
}
- ExtensionAPI extension_api;
-
scoped_ptr<std::set<std::string> > privileged_apis =
- extension_api.GetAPIsForContext(
+ ExtensionAPI::GetInstance()->GetAPIsForContext(
Feature::BLESSED_EXTENSION_CONTEXT, extension.get(), GURL());
scoped_ptr<std::set<std::string> > unprivileged_apis =
- extension_api.GetAPIsForContext(
+ ExtensionAPI::GetInstance()->GetAPIsForContext(
Feature::UNBLESSED_EXTENSION_CONTEXT, extension.get(), GURL());
scoped_ptr<std::set<std::string> > content_script_apis =
- extension_api.GetAPIsForContext(
+ ExtensionAPI::GetInstance()->GetAPIsForContext(
Feature::CONTENT_SCRIPT_CONTEXT, extension.get(), GURL());
// "storage" is completely unprivileged.
@@ -142,7 +119,7 @@ TEST(ExtensionAPI, ExtensionWithDependencies) {
scoped_refptr<Extension> extension =
CreateExtensionWithPermission("ttsEngine");
scoped_ptr<std::set<std::string> > apis =
- ExtensionAPI().GetAPIsForContext(
+ ExtensionAPI::GetInstance()->GetAPIsForContext(
Feature::BLESSED_EXTENSION_CONTEXT, extension.get(), GURL());
EXPECT_EQ(1u, apis->count("ttsEngine"));
EXPECT_EQ(1u, apis->count("tts"));
@@ -154,42 +131,39 @@ TEST(ExtensionAPI, ExtensionWithDependencies) {
scoped_refptr<Extension> extension =
CreateExtensionWithPermission("tts");
scoped_ptr<std::set<std::string> > apis =
- ExtensionAPI().GetAPIsForContext(
+ ExtensionAPI::GetInstance()->GetAPIsForContext(
Feature::BLESSED_EXTENSION_CONTEXT, extension.get(), GURL());
EXPECT_EQ(0u, apis->count("ttsEngine"));
EXPECT_EQ(1u, apis->count("tts"));
}
}
-bool MatchesURL(
- ExtensionAPI* api, const std::string& api_name, const std::string& url) {
+bool MatchesURL(const std::string& api_name, const std::string& url) {
scoped_ptr<std::set<std::string> > apis =
- api->GetAPIsForContext(Feature::WEB_PAGE_CONTEXT, NULL, GURL(url));
+ ExtensionAPI::GetInstance()->GetAPIsForContext(
+ Feature::WEB_PAGE_CONTEXT, NULL, GURL(url));
return apis->count(api_name);
}
TEST(ExtensionAPI, URLMatching) {
- ExtensionAPI api;
-
// "app" API is available to all URLs that content scripts can be injected.
- EXPECT_TRUE(MatchesURL(&api, "app", "http://example.com/example.html"));
- EXPECT_TRUE(MatchesURL(&api, "app", "https://blah.net"));
- EXPECT_TRUE(MatchesURL(&api, "app", "file://somefile.html"));
+ EXPECT_TRUE(MatchesURL("app", "http://example.com/example.html"));
+ EXPECT_TRUE(MatchesURL("app", "https://blah.net"));
+ EXPECT_TRUE(MatchesURL("app", "file://somefile.html"));
// But not internal URLs (for chrome-extension:// the app API is injected by
// GetSchemasForExtension).
- EXPECT_FALSE(MatchesURL(&api, "app", "about:flags"));
- EXPECT_FALSE(MatchesURL(&api, "app", "chrome://flags"));
- EXPECT_FALSE(MatchesURL(&api, "app", "chrome-extension://fakeextension"));
+ EXPECT_FALSE(MatchesURL("app", "about:flags"));
+ EXPECT_FALSE(MatchesURL("app", "chrome://flags"));
+ EXPECT_FALSE(MatchesURL("app", "chrome-extension://fakeextension"));
// "storage" API (for example) isn't available to any URLs.
- EXPECT_FALSE(MatchesURL(&api, "storage", "http://example.com/example.html"));
- EXPECT_FALSE(MatchesURL(&api, "storage", "https://blah.net"));
- EXPECT_FALSE(MatchesURL(&api, "storage", "file://somefile.html"));
- EXPECT_FALSE(MatchesURL(&api, "storage", "about:flags"));
- EXPECT_FALSE(MatchesURL(&api, "storage", "chrome://flags"));
- EXPECT_FALSE(MatchesURL(&api, "storage", "chrome-extension://fakeextension"));
+ EXPECT_FALSE(MatchesURL("storage", "http://example.com/example.html"));
+ EXPECT_FALSE(MatchesURL("storage", "https://blah.net"));
+ EXPECT_FALSE(MatchesURL("storage", "file://somefile.html"));
+ EXPECT_FALSE(MatchesURL("storage", "about:flags"));
+ EXPECT_FALSE(MatchesURL("storage", "chrome://flags"));
+ EXPECT_FALSE(MatchesURL("storage", "chrome-extension://fakeextension"));
}
} // namespace
-} // namespace extensions