summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--chrome/browser/renderer_host/chrome_render_view_host_observer.cc23
-rw-r--r--chrome/chrome_renderer.gypi5
-rw-r--r--chrome/common/common_resources.grd2
-rw-r--r--chrome/common/extensions/api/app.json70
-rw-r--r--chrome/common/extensions/api/extension_api.cc168
-rw-r--r--chrome/common/extensions/api/extension_api.h68
-rw-r--r--chrome/common/extensions/api/extension_api_unittest.cc144
-rw-r--r--chrome/common/extensions/extension_messages.h4
-rw-r--r--chrome/common/extensions/extension_permission_set.cc11
-rw-r--r--chrome/common/extensions/extension_permission_set.h6
-rw-r--r--chrome/common/extensions/feature.cc1
-rw-r--r--chrome/common/extensions/feature.h16
-rw-r--r--chrome/common/extensions/feature_unittest.cc4
-rw-r--r--chrome/renderer/extensions/app_bindings.cc5
-rw-r--r--chrome/renderer/extensions/chrome_v8_context.cc14
-rw-r--r--chrome/renderer/extensions/chrome_v8_context.h16
-rw-r--r--chrome/renderer/extensions/chrome_v8_context_set_unittest.cc9
-rw-r--r--chrome/renderer/extensions/custom_bindings_util.cc92
-rw-r--r--chrome/renderer/extensions/custom_bindings_util.h44
-rw-r--r--chrome/renderer/extensions/extension_custom_bindings.cc3
-rw-r--r--chrome/renderer/extensions/extension_dispatcher.cc223
-rw-r--r--chrome/renderer/extensions/extension_dispatcher.h26
-rw-r--r--chrome/renderer/extensions/schema_generated_bindings.cc43
-rw-r--r--chrome/renderer/renderer_resources.grd5
-rw-r--r--chrome/renderer/resource_bundle_source_map.cc2
-rw-r--r--chrome/renderer/resources/extensions/app.js41
-rw-r--r--chrome/renderer/resources/extensions/app_custom_bindings.js52
-rw-r--r--chrome/renderer/resources/extensions/schema_generated_bindings.js5
-rw-r--r--chrome/renderer/resources/extensions/setup_bindings.js16
-rw-r--r--chrome/test/data/extensions/api_test/content_scripts/extension_iframe/iframe.js12
-rw-r--r--chrome/test/data/extensions/api_test/stubs/content_script.js8
31 files changed, 616 insertions, 522 deletions
diff --git a/chrome/browser/renderer_host/chrome_render_view_host_observer.cc b/chrome/browser/renderer_host/chrome_render_view_host_observer.cc
index 91da264..67a9acb 100644
--- a/chrome/browser/renderer_host/chrome_render_view_host_observer.cc
+++ b/chrome/browser/renderer_host/chrome_render_view_host_observer.cc
@@ -104,7 +104,6 @@ void ChromeRenderViewHostObserver::InitRenderViewForExtensions() {
content::RenderProcessHost* process = render_view_host()->GetProcess();
if (extension->is_app()) {
- Send(new ExtensionMsg_ActivateApplication(extension->id()));
// Though we already record the associated process ID for the renderer in
// InitRenderViewHostForExtensions, the process might have crashed and been
// restarted (hence the re-initialization), so we need to update that
@@ -127,13 +126,21 @@ void ChromeRenderViewHostObserver::InitRenderViewForExtensions() {
}
}
- if (type == Extension::TYPE_EXTENSION ||
- type == Extension::TYPE_USER_SCRIPT ||
- type == Extension::TYPE_PACKAGED_APP ||
- type == Extension::TYPE_PLATFORM_APP ||
- (type == Extension::TYPE_HOSTED_APP &&
- extension->location() == Extension::COMPONENT)) {
- Send(new ExtensionMsg_ActivateExtension(extension->id()));
+ switch (type) {
+ case Extension::TYPE_EXTENSION:
+ case Extension::TYPE_USER_SCRIPT:
+ case Extension::TYPE_HOSTED_APP:
+ case Extension::TYPE_PACKAGED_APP:
+ case Extension::TYPE_PLATFORM_APP:
+ Send(new ExtensionMsg_ActivateExtension(extension->id()));
+ break;
+
+ case Extension::TYPE_UNKNOWN:
+ case Extension::TYPE_THEME:
+ break;
+
+ default:
+ NOTREACHED();
}
}
diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi
index b986668..07ae202 100644
--- a/chrome/chrome_renderer.gypi
+++ b/chrome/chrome_renderer.gypi
@@ -74,8 +74,6 @@
'renderer/extensions/chrome_v8_extension_handler.h',
'renderer/extensions/context_menus_custom_bindings.cc',
'renderer/extensions/context_menus_custom_bindings.h',
- 'renderer/extensions/custom_bindings_util.cc',
- 'renderer/extensions/custom_bindings_util.h',
'renderer/extensions/event_bindings.cc',
'renderer/extensions/event_bindings.h',
'renderer/extensions/experimental.socket_custom_bindings.cc',
@@ -130,7 +128,7 @@
'renderer/resource_bundle_source_map.cc',
'renderer/resource_bundle_source_map.h',
'renderer/resources/extensions/apitest.js',
- 'renderer/resources/extensions/app.js',
+ 'renderer/resources/extensions/app_custom_bindings.js',
'renderer/resources/extensions/browser_action_custom_bindings.js',
'renderer/resources/extensions/chrome_private_custom_bindings.js',
'renderer/resources/extensions/context_menus_custom_bindings.js',
@@ -150,7 +148,6 @@
'renderer/resources/extensions/page_actions_custom_bindings.js',
'renderer/resources/extensions/page_capture_custom_bindings.js',
'renderer/resources/extensions/schema_generated_bindings.js',
- 'renderer/resources/extensions/setup_bindings.js',
'renderer/resources/extensions/tts_custom_bindings.js',
'renderer/resources/extensions/tts_engine_custom_bindings.js',
'renderer/resources/extensions/types_custom_bindings.js',
diff --git a/chrome/common/common_resources.grd b/chrome/common/common_resources.grd
index 536fd1b..e898d36 100644
--- a/chrome/common/common_resources.grd
+++ b/chrome/common/common_resources.grd
@@ -11,6 +11,8 @@
<includes>
<include name="IDR_EXTENSION_MANIFEST_FEATURES" file="extensions\api\_manifest_features.json" type="BINDATA" />
<include name="IDR_EXTENSION_PERMISSION_FEATURES" file="extensions\api\_permission_features.json" type="BINDATA" />
+
+ <include name="IDR_EXTENSION_API_JSON_APP" file="extensions\api\app.json" type="BINDATA" />
<include name="IDR_EXTENSION_API_JSON_BOOKMARKS" file="extensions\api\bookmarks.json" type="BINDATA" />
<include name="IDR_EXTENSION_API_JSON_BROWSERACTION" file="extensions\api\browserAction.json" type="BINDATA" />
<include name="IDR_EXTENSION_API_JSON_BROWSING_DATA" file="extensions\api\browsingData.json" type="BINDATA" />
diff --git a/chrome/common/extensions/api/app.json b/chrome/common/extensions/api/app.json
new file mode 100644
index 0000000..0e813e6
--- /dev/null
+++ b/chrome/common/extensions/api/app.json
@@ -0,0 +1,70 @@
+[
+ {
+ "namespace": "app",
+ "nodoc": true,
+ "unprivileged": true,
+ "matches": [ "<all_urls>" ],
+ "types": [
+ {
+ "id": "Details",
+ "description": "TODO (it's a manifest)",
+ "type": "object",
+ "properties": {},
+ "additionalProperties": { "type": "any" }
+ },
+ {
+ "id": "DOMWindow",
+ "type": "object",
+ "properties": {},
+ "additionalProperties": { "type": "any" }
+ }
+ ],
+ "functions": [
+ {
+ "name": "getIsInstalled",
+ "description": "TODO",
+ "type": "function",
+ "parameters": [],
+ "returns": {
+ "name": "isInstalled",
+ "description": "TODO",
+ "type": "boolean"
+ }
+ },
+ {
+ "name": "install",
+ "description": "TODO",
+ "type": "function",
+ "parameters": []
+ },
+ {
+ "name": "getDetails",
+ "description": "TODO",
+ "type": "function",
+ "parameters": [],
+ "returns": {
+ "$ref": "Details",
+ "optional": true,
+ "description": "TODO"
+ }
+ },
+ {
+ "name": "getDetailsForFrame",
+ "description": "TODO",
+ "type": "function",
+ "parameters": [
+ {
+ "name": "frame",
+ "description": "TODO",
+ "$ref": "DOMWindow"
+ }
+ ],
+ "returns": {
+ "$ref": "Details",
+ "optional": true,
+ "description": "TODO"
+ }
+ }
+ ]
+ }
+]
diff --git a/chrome/common/extensions/api/extension_api.cc b/chrome/common/extensions/api/extension_api.cc
index f8909b0..a36989d 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
diff --git a/chrome/common/extensions/api/extension_api.h b/chrome/common/extensions/api/extension_api.h
index 25ac679..6e2c604 100644
--- a/chrome/common/extensions/api/extension_api.h
+++ b/chrome/common/extensions/api/extension_api.h
@@ -12,8 +12,11 @@
#include "base/basictypes.h"
#include "base/memory/linked_ptr.h"
+#include "base/memory/scoped_ptr.h"
#include "base/memory/singleton.h"
#include "base/values.h"
+#include "chrome/common/extensions/feature.h"
+#include "chrome/common/extensions/url_pattern_set.h"
namespace base {
class DictionaryValue;
@@ -21,6 +24,7 @@ class ListValue;
class Value;
}
+class GURL;
class Extension;
class ExtensionPermissionSet;
@@ -29,18 +33,6 @@ namespace extensions {
// C++ Wrapper for the JSON API definitions in chrome/common/extensions/api/.
class ExtensionAPI {
public:
- // Filtering option for the GetSchemas functions.
- enum GetSchemasFilter {
- // Returns all schemas that an extension has permission for.
- ALL,
-
- // Returns schemas for only APIs with unprivileged components (i.e. those
- // where !IsWholeAPIPrivileged).
- ONLY_UNPRIVILEGED
- };
-
- typedef std::map<std::string, linked_ptr<const DictionaryValue> > SchemaMap;
-
// Returns the single instance of this class.
static ExtensionAPI* GetInstance();
@@ -50,26 +42,17 @@ class ExtensionAPI {
// content scripts, or other low-privileged contexts.
bool IsPrivileged(const std::string& name) const;
- // Returns whether *every* path in the API is privileged. This will be false
- // for APIs such as "storage" which is entirely unprivileged, and "test"
- // which has unprivileged components.
- bool IsWholeAPIPrivileged(const std::string& api_name) const;
-
- // Gets a map of API name (aka namespace) to API schema.
- const SchemaMap& schemas() { return schemas_; }
-
// 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;
- // Gets the API schemas that are available to an Extension.
- void GetSchemasForExtension(const Extension& extension,
- GetSchemasFilter filter,
- SchemaMap* out) const;
-
- // Gets the schemas for the default set of APIs that are available to every
- // extension.
- void GetDefaultSchemas(GetSchemasFilter filter, SchemaMap* out) 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) const;
private:
friend struct DefaultSingletonTraits<ExtensionAPI>;
@@ -93,18 +76,34 @@ class ExtensionAPI {
const std::string& child_kind,
const std::string& child_name) const;
- // Gets the schemas for the APIs that are allowed by a permission set.
- void GetSchemasForPermissions(const ExtensionPermissionSet& permissions,
- GetSchemasFilter filter,
- SchemaMap* out) 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) const;
// Adds dependent schemas to |out| as determined by the "dependencies"
// property.
- void ResolveDependencies(SchemaMap* out) const;
+ 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) 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) const;
+
+ // Adds an APIs that match |url| to |out|.
+ void GetAPIsMatchingURL(const GURL& url, std::set<std::string>* out) const;
static ExtensionAPI* instance_;
// Schemas for each namespace.
+ typedef std::map<std::string, linked_ptr<const DictionaryValue> > SchemaMap;
SchemaMap schemas_;
// APIs that are entirely unprivileged.
@@ -113,6 +112,9 @@ class ExtensionAPI {
// APIs that are not entirely unprivileged, but have unprivileged components.
std::set<std::string> partially_unprivileged_apis_;
+ // APIs that have URL matching permissions.
+ std::map<std::string, URLPatternSet> url_matching_apis_;
+
DISALLOW_COPY_AND_ASSIGN(ExtensionAPI);
};
diff --git a/chrome/common/extensions/api/extension_api_unittest.cc b/chrome/common/extensions/api/extension_api_unittest.cc
index 70982f7..3f4a0af 100644
--- a/chrome/common/extensions/api/extension_api_unittest.cc
+++ b/chrome/common/extensions/api/extension_api_unittest.cc
@@ -13,7 +13,10 @@
#include "chrome/common/extensions/extension.h"
#include "testing/gtest/include/gtest/gtest.h"
+namespace {
+
using extensions::ExtensionAPI;
+using extensions::Feature;
TEST(ExtensionAPI, IsPrivileged) {
ExtensionAPI* extension_api = ExtensionAPI::GetInstance();
@@ -33,6 +36,8 @@ TEST(ExtensionAPI, IsPrivileged) {
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"));
@@ -40,34 +45,18 @@ TEST(ExtensionAPI, IsPrivileged) {
EXPECT_FALSE(extension_api->IsPrivileged("storage.set"));
}
-TEST(ExtensionAPI, IsWholeAPIPrivileged) {
- ExtensionAPI* extension_api = ExtensionAPI::GetInstance();
-
- // Completely unprivileged.
- EXPECT_FALSE(extension_api->IsWholeAPIPrivileged("storage"));
-
- // Partially unprivileged.
- EXPECT_FALSE(extension_api->IsWholeAPIPrivileged("extension"));
- EXPECT_FALSE(extension_api->IsWholeAPIPrivileged("test"));
-
- // Nothing unprivileged.
- EXPECT_TRUE(extension_api->IsWholeAPIPrivileged("history"));
-
- // Paranoid above... paranoid here, too.
- EXPECT_TRUE(extension_api->IsWholeAPIPrivileged(""));
- EXPECT_TRUE(extension_api->IsWholeAPIPrivileged("<unknown-namespace>"));
-}
-
-TEST(ExtensionAPI, Depends) {
- // Fake extension with the "ttsEngine" permission but not the "tts"
- // permission; it must load TTS.
+scoped_refptr<Extension> CreateExtensionWithPermissions(
+ const std::set<std::string>& permissions) {
DictionaryValue manifest;
- manifest.SetString("name", "test extension");
+ manifest.SetString("name", "extension");
manifest.SetString("version", "1.0");
{
- scoped_ptr<ListValue> permissions(new ListValue());
- permissions->Append(Value::CreateStringValue("ttsEngine"));
- manifest.Set("permissions", permissions.release());
+ scoped_ptr<ListValue> permissions_list(new ListValue());
+ for (std::set<std::string>::const_iterator i = permissions.begin();
+ i != permissions.end(); ++i) {
+ permissions_list->Append(Value::CreateStringValue(*i));
+ }
+ manifest.Set("permissions", permissions_list.release());
}
std::string error;
@@ -76,8 +65,105 @@ TEST(ExtensionAPI, Depends) {
CHECK(extension.get());
CHECK(error.empty());
- ExtensionAPI::SchemaMap schemas;
- ExtensionAPI::GetInstance()->GetSchemasForExtension(
- *extension, ExtensionAPI::ALL, &schemas);
- EXPECT_EQ(1u, schemas.count("tts"));
+ return extension;
+}
+
+scoped_refptr<Extension> CreateExtensionWithPermission(
+ const std::string& permission) {
+ std::set<std::string> permissions;
+ permissions.insert(permission);
+ return CreateExtensionWithPermissions(permissions);
+}
+
+TEST(ExtensionAPI, ExtensionWithUnprivilegedAPIs) {
+ scoped_refptr<Extension> extension;
+ {
+ std::set<std::string> permissions;
+ permissions.insert("storage");
+ permissions.insert("history");
+ extension = CreateExtensionWithPermissions(permissions);
+ }
+
+ scoped_ptr<std::set<std::string> > privileged_apis =
+ ExtensionAPI::GetInstance()->GetAPIsForContext(
+ Feature::PRIVILEGED_CONTEXT, extension.get(), GURL());
+
+ scoped_ptr<std::set<std::string> > unprivileged_apis =
+ ExtensionAPI::GetInstance()->GetAPIsForContext(
+ Feature::UNPRIVILEGED_CONTEXT, extension.get(), GURL());
+
+ scoped_ptr<std::set<std::string> > content_script_apis =
+ ExtensionAPI::GetInstance()->GetAPIsForContext(
+ Feature::CONTENT_SCRIPT_CONTEXT, extension.get(), GURL());
+
+ // "storage" is completely unprivileged.
+ EXPECT_EQ(1u, privileged_apis->count("storage"));
+ EXPECT_EQ(1u, unprivileged_apis->count("storage"));
+ EXPECT_EQ(1u, content_script_apis->count("storage"));
+
+ // "extension" is partially unprivileged.
+ EXPECT_EQ(1u, privileged_apis->count("extension"));
+ EXPECT_EQ(1u, unprivileged_apis->count("extension"));
+ EXPECT_EQ(1u, content_script_apis->count("extension"));
+
+ // "history" is entirely privileged.
+ EXPECT_EQ(1u, privileged_apis->count("history"));
+ EXPECT_EQ(0u, unprivileged_apis->count("history"));
+ EXPECT_EQ(0u, content_script_apis->count("history"));
+}
+
+TEST(ExtensionAPI, ExtensionWithDependencies) {
+ // Extension with the "ttsEngine" permission but not the "tts" permission; it
+ // must load TTS.
+ {
+ scoped_refptr<Extension> extension =
+ CreateExtensionWithPermission("ttsEngine");
+ scoped_ptr<std::set<std::string> > apis =
+ ExtensionAPI::GetInstance()->GetAPIsForContext(
+ Feature::PRIVILEGED_CONTEXT, extension.get(), GURL());
+ EXPECT_EQ(1u, apis->count("ttsEngine"));
+ EXPECT_EQ(1u, apis->count("tts"));
+ }
+
+ // Conversely, extension with the "tts" permission but not the "ttsEngine"
+ // permission shouldn't get the "ttsEngine" permission.
+ {
+ scoped_refptr<Extension> extension =
+ CreateExtensionWithPermission("tts");
+ scoped_ptr<std::set<std::string> > apis =
+ ExtensionAPI::GetInstance()->GetAPIsForContext(
+ Feature::PRIVILEGED_CONTEXT, extension.get(), GURL());
+ EXPECT_EQ(0u, apis->count("ttsEngine"));
+ EXPECT_EQ(1u, apis->count("tts"));
+ }
+}
+
+bool MatchesURL(const std::string& api_name, const std::string& url) {
+ scoped_ptr<std::set<std::string> > apis =
+ ExtensionAPI::GetInstance()->GetAPIsForContext(
+ Feature::WEB_PAGE_CONTEXT, NULL, GURL(url));
+ return apis->count(api_name);
+}
+
+TEST(ExtensionAPI, URLMatching) {
+ // "app" API is available to all URLs that content scripts can be injected.
+ 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("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("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
diff --git a/chrome/common/extensions/extension_messages.h b/chrome/common/extensions/extension_messages.h
index 276020e..7fcd56f 100644
--- a/chrome/common/extensions/extension_messages.h
+++ b/chrome/common/extensions/extension_messages.h
@@ -193,10 +193,6 @@ IPC_MESSAGE_CONTROL1(ExtensionMsg_SetFunctionNames,
IPC_MESSAGE_CONTROL1(ExtensionMsg_ActivateExtension,
std::string /* extension_id */)
-// Marks an application as 'active' in a process.
-IPC_MESSAGE_CONTROL1(ExtensionMsg_ActivateApplication,
- std::string /* extension_id */)
-
// Notifies the renderer that extensions were loaded in the browser.
IPC_MESSAGE_CONTROL1(ExtensionMsg_Loaded,
std::vector<ExtensionMsg_Loaded_Params>)
diff --git a/chrome/common/extensions/extension_permission_set.cc b/chrome/common/extensions/extension_permission_set.cc
index 60ed1fa..8dcbab2 100644
--- a/chrome/common/extensions/extension_permission_set.cc
+++ b/chrome/common/extensions/extension_permission_set.cc
@@ -42,6 +42,7 @@ bool RcdBetterThan(std::string a, std::string b) {
// Names of API modules that can be used without listing it in the
// permissions section of the manifest.
const char* kNonPermissionModuleNames[] = {
+ "app",
"browserAction",
"devtools",
"extension",
@@ -565,6 +566,16 @@ std::set<std::string> ExtensionPermissionSet::GetAPIsAsStrings() const {
return apis_str;
}
+std::set<std::string> ExtensionPermissionSet::
+ GetAPIsWithAnyAccessAsStrings() const {
+ std::set<std::string> result = GetAPIsAsStrings();
+ for (size_t i = 0; i < kNumNonPermissionModuleNames; ++i)
+ result.insert(kNonPermissionModuleNames[i]);
+ for (size_t i = 0; i < kNumNonPermissionFunctionNames; ++i)
+ result.insert(GetPermissionName(kNonPermissionFunctionNames[i]));
+ return result;
+}
+
bool ExtensionPermissionSet::HasAnyAccessToAPI(
const std::string& api_name) const {
if (HasAccessToFunction(api_name))
diff --git a/chrome/common/extensions/extension_permission_set.h b/chrome/common/extensions/extension_permission_set.h
index 35418a9..cec4078 100644
--- a/chrome/common/extensions/extension_permission_set.h
+++ b/chrome/common/extensions/extension_permission_set.h
@@ -318,6 +318,12 @@ class ExtensionPermissionSet
// Gets the API permissions in this set as a set of strings.
std::set<std::string> GetAPIsAsStrings() const;
+ // Gets the API permissions in this set, plus any that have implicit access
+ // (such as APIs that require no permissions, or APIs with functions that
+ // require no permissions).
+ // TODO(kalman): return scoped_ptr to avoid copying.
+ std::set<std::string> GetAPIsWithAnyAccessAsStrings() const;
+
// Returns whether this namespace has any functions which the extension has
// permission to use. For example, even though the extension may not have
// the "tabs" permission, "tabs.create" requires no permissions so
diff --git a/chrome/common/extensions/feature.cc b/chrome/common/extensions/feature.cc
index 79e8338..d511c19 100644
--- a/chrome/common/extensions/feature.cc
+++ b/chrome/common/extensions/feature.cc
@@ -24,6 +24,7 @@ struct Mappings {
contexts["privileged"] = extensions::Feature::PRIVILEGED_CONTEXT;
contexts["unprivileged"] = extensions::Feature::UNPRIVILEGED_CONTEXT;
contexts["content_script"] = extensions::Feature::CONTENT_SCRIPT_CONTEXT;
+ contexts["web_page"] = extensions::Feature::WEB_PAGE_CONTEXT;
locations["component"] = extensions::Feature::COMPONENT_LOCATION;
diff --git a/chrome/common/extensions/feature.h b/chrome/common/extensions/feature.h
index 61a96a5..749f4b3 100644
--- a/chrome/common/extensions/feature.h
+++ b/chrome/common/extensions/feature.h
@@ -22,11 +22,21 @@ namespace extensions {
class Feature {
public:
// The JavaScript contexts the feature is supported in.
+ // TODO(kalman): s/PRIVILEGED/BLESSED_EXTENSION/
enum Context {
UNSPECIFIED_CONTEXT,
- PRIVILEGED_CONTEXT, // A context in a privileged extension process.
- UNPRIVILEGED_CONTEXT, // A context in a normal, unprivileged renderer.
- CONTENT_SCRIPT_CONTEXT // A context from a content script.
+
+ // A context in a privileged extension process.
+ PRIVILEGED_CONTEXT,
+
+ // A context in a normal, unprivileged renderer.
+ UNPRIVILEGED_CONTEXT,
+
+ // A context from a content script.
+ CONTENT_SCRIPT_CONTEXT,
+
+ // A normal web page. This should have an associated URL matching pattern.
+ WEB_PAGE_CONTEXT,
};
// The location required of extensions the feature is supported in.
diff --git a/chrome/common/extensions/feature_unittest.cc b/chrome/common/extensions/feature_unittest.cc
index 8147ca7..432e4ac 100644
--- a/chrome/common/extensions/feature_unittest.cc
+++ b/chrome/common/extensions/feature_unittest.cc
@@ -236,12 +236,14 @@ TEST(ExtensionFeatureTest, ParseContexts) {
contexts->Append(Value::CreateStringValue("privileged"));
contexts->Append(Value::CreateStringValue("unprivileged"));
contexts->Append(Value::CreateStringValue("content_script"));
+ contexts->Append(Value::CreateStringValue("web_page"));
value->Set("contexts", contexts);
scoped_ptr<Feature> feature(Feature::Parse(value.get()));
- EXPECT_EQ(3u, feature->contexts()->size());
+ EXPECT_EQ(4u, feature->contexts()->size());
EXPECT_TRUE(feature->contexts()->count(Feature::PRIVILEGED_CONTEXT));
EXPECT_TRUE(feature->contexts()->count(Feature::UNPRIVILEGED_CONTEXT));
EXPECT_TRUE(feature->contexts()->count(Feature::CONTENT_SCRIPT_CONTEXT));
+ EXPECT_TRUE(feature->contexts()->count(Feature::WEB_PAGE_CONTEXT));
value->SetString("contexts", "all");
scoped_ptr<Feature> feature2(Feature::Parse(value.get()));
diff --git a/chrome/renderer/extensions/app_bindings.cc b/chrome/renderer/extensions/app_bindings.cc
index 34c8047..a5a902a 100644
--- a/chrome/renderer/extensions/app_bindings.cc
+++ b/chrome/renderer/extensions/app_bindings.cc
@@ -55,7 +55,6 @@ const char* kInvalidCallbackIdError = "Invalid callbackId";
} // namespace
-
AppBindings::AppBindings(ExtensionDispatcher* dispatcher,
ChromeV8Context* context)
: ChromeV8Extension(dispatcher),
@@ -72,7 +71,6 @@ AppBindings::AppBindings(ExtensionDispatcher* dispatcher,
base::Bind(&AppBindings::GetAppNotifyChannel, base::Unretained(this)));
}
-
v8::Handle<v8::Value> AppBindings::GetIsInstalled(
const v8::Arguments& args) {
// TODO(aa): Hm, maybe ExtensionBindingsContext should have GetExtension()
@@ -81,9 +79,8 @@ v8::Handle<v8::Value> AppBindings::GetIsInstalled(
extension_dispatcher_->extensions()->GetByID(context_->extension_id());
// TODO(aa): Why only hosted app?
- // TODO(aa): GARRR - why is there IsExtensionActive and IsApplicationActive!?
bool result = extension && extension->is_hosted_app() &&
- extension_dispatcher_->IsApplicationActive(extension->id());
+ extension_dispatcher_->IsExtensionActive(extension->id());
return v8::Boolean::New(result);
}
diff --git a/chrome/renderer/extensions/chrome_v8_context.cc b/chrome/renderer/extensions/chrome_v8_context.cc
index 7db10ed..6d59a19 100644
--- a/chrome/renderer/extensions/chrome_v8_context.cc
+++ b/chrome/renderer/extensions/chrome_v8_context.cc
@@ -15,6 +15,8 @@
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
#include "v8/include/v8.h"
+using extensions::Feature;
+
namespace {
const char kChromeHidden[] = "chromeHidden";
@@ -24,11 +26,13 @@ const char kValidateCallbacks[] = "validateCallbacks";
const char kValidateAPI[] = "validateAPI";
#endif
-std::string GetContextTypeDescription(
- ChromeV8Context::ContextType context_type) {
+std::string GetContextTypeDescription(Feature::Context context_type) {
switch (context_type) {
- case ChromeV8Context::OTHER: return "other";
- case ChromeV8Context::CONTENT_SCRIPT: return "content script";
+ case Feature::UNSPECIFIED_CONTEXT: return "unspecified";
+ case Feature::PRIVILEGED_CONTEXT: return "privileged";
+ case Feature::UNPRIVILEGED_CONTEXT: return "unprivileged";
+ case Feature::CONTENT_SCRIPT_CONTEXT: return "content script";
+ case Feature::WEB_PAGE_CONTEXT: return "web page";
}
NOTREACHED();
return "";
@@ -39,7 +43,7 @@ std::string GetContextTypeDescription(
ChromeV8Context::ChromeV8Context(v8::Handle<v8::Context> v8_context,
WebKit::WebFrame* web_frame,
const std::string& extension_id,
- ChromeV8Context::ContextType context_type)
+ Feature::Context context_type)
: v8_context_(v8::Persistent<v8::Context>::New(v8_context)),
web_frame_(web_frame),
extension_id_(extension_id),
diff --git a/chrome/renderer/extensions/chrome_v8_context.h b/chrome/renderer/extensions/chrome_v8_context.h
index 3faf9d2..e2c8911 100644
--- a/chrome/renderer/extensions/chrome_v8_context.h
+++ b/chrome/renderer/extensions/chrome_v8_context.h
@@ -9,6 +9,7 @@
#include <string>
#include "base/basictypes.h"
+#include "chrome/common/extensions/feature.h"
#include "chrome/renderer/module_system.h"
#include "v8/include/v8.h"
@@ -27,19 +28,10 @@ class RenderView;
// we won't need this object and it's a bit less state to keep track of.
class ChromeV8Context {
public:
- enum ContextType {
- CONTENT_SCRIPT,
-
- // TODO(kalman): for now, have this as OTHER, since we only currently need
- // know whether something is a content script or not. However, when
- // necessary this should enumerate the other types, such as FRAME.
- OTHER
- };
-
ChromeV8Context(v8::Handle<v8::Context> context,
WebKit::WebFrame* frame,
const std::string& extension_id,
- ContextType context_type);
+ extensions::Feature::Context context_type);
~ChromeV8Context();
v8::Handle<v8::Context> v8_context() const {
@@ -57,7 +49,7 @@ class ChromeV8Context {
web_frame_ = NULL;
}
- ContextType context_type() const {
+ extensions::Feature::Context context_type() const {
return context_type_;
}
@@ -116,7 +108,7 @@ class ChromeV8Context {
std::string extension_id_;
// The type of context.
- ContextType context_type_;
+ extensions::Feature::Context context_type_;
// Owns and structures the JS that is injected to set up extension bindings.
scoped_ptr<ModuleSystem> module_system_;
diff --git a/chrome/renderer/extensions/chrome_v8_context_set_unittest.cc b/chrome/renderer/extensions/chrome_v8_context_set_unittest.cc
index 56f4697..af7b17d 100644
--- a/chrome/renderer/extensions/chrome_v8_context_set_unittest.cc
+++ b/chrome/renderer/extensions/chrome_v8_context_set_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "base/message_loop.h"
+#include "chrome/common/extensions/feature.h"
#include "chrome/renderer/extensions/chrome_v8_context.h"
#include "chrome/renderer/extensions/chrome_v8_context_set.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -21,9 +22,11 @@ TEST(ChromeV8ContextSet, Lifecycle) {
// creating a whole webview.
WebKit::WebFrame* frame = reinterpret_cast<WebKit::WebFrame*>(1);
std::string extension_id = "00000000000000000000000000000000";
- ChromeV8Context* context =
- new ChromeV8Context(
- v8_context, frame, extension_id, ChromeV8Context::OTHER);
+ ChromeV8Context* context = new ChromeV8Context(
+ v8_context,
+ frame,
+ extension_id,
+ extensions::Feature::PRIVILEGED_CONTEXT);
context_set.Add(context);
EXPECT_EQ(1u, context_set.GetAll().count(context));
diff --git a/chrome/renderer/extensions/custom_bindings_util.cc b/chrome/renderer/extensions/custom_bindings_util.cc
deleted file mode 100644
index 5de0470b..0000000
--- a/chrome/renderer/extensions/custom_bindings_util.cc
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#include "chrome/renderer/extensions/custom_bindings_util.h"
-
-#include <map>
-
-#include "base/logging.h"
-#include "base/string_util.h"
-#include "chrome/common/extensions/api/extension_api.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/renderer/extensions/chrome_v8_extension.h"
-#include "chrome/renderer/extensions/chrome_private_custom_bindings.h"
-#include "chrome/renderer/extensions/context_menus_custom_bindings.h"
-#include "chrome/renderer/extensions/experimental.socket_custom_bindings.h"
-#include "chrome/renderer/extensions/extension_custom_bindings.h"
-#include "chrome/renderer/extensions/extension_dispatcher.h"
-#include "chrome/renderer/extensions/file_browser_handler_custom_bindings.h"
-#include "chrome/renderer/extensions/file_browser_private_custom_bindings.h"
-#include "chrome/renderer/extensions/i18n_custom_bindings.h"
-#include "chrome/renderer/extensions/page_actions_custom_bindings.h"
-#include "chrome/renderer/extensions/page_capture_custom_bindings.h"
-#include "chrome/renderer/extensions/tabs_custom_bindings.h"
-#include "chrome/renderer/extensions/tts_custom_bindings.h"
-#include "chrome/renderer/extensions/web_request_custom_bindings.h"
-#include "grit/renderer_resources.h"
-#include "v8/include/v8.h"
-
-namespace extensions {
-
-namespace custom_bindings_util {
-
-// Extracts the name of an API from the name of the V8 extension which contains
-// custom bindings for it (see kCustomBindingNames).
-std::string GetAPIName(const std::string& v8_extension_name) {
- // Extract the name of the API from the v8 extension name.
- // This is "${api_name}" in "extensions/${api_name}_custom_bindings.js".
- std::string prefix = "extensions/";
- const bool kCaseSensitive = true;
- if (!StartsWithASCII(v8_extension_name, prefix, kCaseSensitive))
- return "";
-
- std::string suffix = "_custom_bindings.js";
- if (!EndsWith(v8_extension_name, suffix, kCaseSensitive))
- return "";
-
- // By convention, filenames are use unix_hacker_style, but the APIs we expose
- // to javascript use camelCase.
- std::string not_camelcase = v8_extension_name.substr(
- prefix.size(),
- v8_extension_name.size() - prefix.size() - suffix.size());
-
- std::string camelcase;
- bool next_to_upper = false;
- for (std::string::iterator it = not_camelcase.begin();
- it != not_camelcase.end(); ++it) {
- if (*it == '_') {
- next_to_upper = true;
- } else if (next_to_upper) {
- camelcase.push_back(base::ToUpperASCII(*it));
- next_to_upper = false;
- } else {
- camelcase.push_back(*it);
- }
- }
-
- return camelcase;
-}
-
-bool AllowAPIInjection(const std::string& api_name,
- const Extension& extension,
- ExtensionDispatcher* extension_dispatcher) {
- CHECK(api_name != "");
-
- // As in ExtensionAPI::GetSchemasForExtension, we need to allow any bindings
- // for an API that the extension *might* have permission to use.
- bool allowed =
- extension.required_permission_set()->HasAnyAccessToAPI(api_name) ||
- extension.optional_permission_set()->HasAnyAccessToAPI(api_name);
-
- if (extension_dispatcher->is_extension_process()) {
- return allowed;
- } else {
- return allowed &&
- !ExtensionAPI::GetInstance()->IsWholeAPIPrivileged(api_name);
- }
-}
-
-} // namespace custom_bindings_util
-
-} // namespace extensions
diff --git a/chrome/renderer/extensions/custom_bindings_util.h b/chrome/renderer/extensions/custom_bindings_util.h
deleted file mode 100644
index 73d026d..0000000
--- a/chrome/renderer/extensions/custom_bindings_util.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-#ifndef CHROME_RENDERER_EXTENSIONS_CUSTOM_BINDINGS_UTIL_H_
-#define CHROME_RENDERER_EXTENSIONS_CUSTOM_BINDINGS_UTIL_H_
-#pragma once
-
-#include <string>
-#include <vector>
-
-#include "chrome/renderer/extensions/chrome_v8_extension.h"
-
-class Extension;
-class ExtensionDispatcher;
-
-namespace v8 {
-class Extension;
-}
-
-namespace extensions {
-
-// Utilities for managing the set of V8 extensions for extension API custom
-// bindings.
-namespace custom_bindings_util {
-
-// Extracts the name of an API from the name of the V8 extension which contains
-// custom bindings for it.
-// Returns an empty string if the extension is not for a custom binding.
-std::string GetAPIName(const std::string& v8_extension_name);
-
-// Returns whether the custom binding for an API should be allowed to run for
-// |extension|. This is based on whether the extension has any permission
-// (required or optional) for that API, and what context the APIs are intended
-// to run in.
-bool AllowAPIInjection(const std::string& api_name,
- const Extension& extension,
- ExtensionDispatcher* extension_dispatcher);
-
-} // namespace custom_bindings_util
-
-} // namespace extensions
-
-#endif // CHROME_RENDERER_EXTENSIONS_CUSTOM_BINDINGS_UTIL_H_
diff --git a/chrome/renderer/extensions/extension_custom_bindings.cc b/chrome/renderer/extensions/extension_custom_bindings.cc
index c4895cd..afb45e0 100644
--- a/chrome/renderer/extensions/extension_custom_bindings.cc
+++ b/chrome/renderer/extensions/extension_custom_bindings.cc
@@ -22,9 +22,6 @@
#include "v8/include/v8.h"
#include "webkit/glue/webkit_glue.h"
-using WebKit::WebFrame;
-using WebKit::WebView;
-
namespace extensions {
namespace {
diff --git a/chrome/renderer/extensions/extension_dispatcher.cc b/chrome/renderer/extensions/extension_dispatcher.cc
index 4d187bb2..f3d44df 100644
--- a/chrome/renderer/extensions/extension_dispatcher.cc
+++ b/chrome/renderer/extensions/extension_dispatcher.cc
@@ -10,6 +10,7 @@
#include "base/string_piece.h"
#include "chrome/common/child_process_logging.h"
#include "chrome/common/chrome_switches.h"
+#include "chrome/common/extensions/api/extension_api.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_messages.h"
#include "chrome/common/extensions/extension_permission_set.h"
@@ -18,12 +19,23 @@
#include "chrome/renderer/extensions/app_bindings.h"
#include "chrome/renderer/extensions/chrome_v8_context.h"
#include "chrome/renderer/extensions/chrome_v8_extension.h"
-#include "chrome/renderer/extensions/custom_bindings_util.h"
+#include "chrome/renderer/extensions/chrome_private_custom_bindings.h"
+#include "chrome/renderer/extensions/context_menus_custom_bindings.h"
#include "chrome/renderer/extensions/event_bindings.h"
+#include "chrome/renderer/extensions/experimental.socket_custom_bindings.h"
+#include "chrome/renderer/extensions/extension_custom_bindings.h"
#include "chrome/renderer/extensions/extension_groups.h"
+#include "chrome/renderer/extensions/file_browser_handler_custom_bindings.h"
+#include "chrome/renderer/extensions/file_browser_private_custom_bindings.h"
+#include "chrome/renderer/extensions/i18n_custom_bindings.h"
#include "chrome/renderer/extensions/miscellaneous_bindings.h"
+#include "chrome/renderer/extensions/page_actions_custom_bindings.h"
+#include "chrome/renderer/extensions/page_capture_custom_bindings.h"
#include "chrome/renderer/extensions/schema_generated_bindings.h"
+#include "chrome/renderer/extensions/tabs_custom_bindings.h"
+#include "chrome/renderer/extensions/tts_custom_bindings.h"
#include "chrome/renderer/extensions/user_script_slave.h"
+#include "chrome/renderer/extensions/web_request_custom_bindings.h"
#include "chrome/renderer/extensions/webstore_bindings.h"
#include "chrome/renderer/module_system.h"
#include "chrome/renderer/native_handler.h"
@@ -33,32 +45,21 @@
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDataSource.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebScopedUserGesture.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebSecurityPolicy.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebURLRequest.h"
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebScopedUserGesture.h"
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
#include "ui/base/resource/resource_bundle.h"
#include "v8/include/v8.h"
-#include "chrome/renderer/extensions/chrome_private_custom_bindings.h"
-#include "chrome/renderer/extensions/context_menus_custom_bindings.h"
-#include "chrome/renderer/extensions/experimental.socket_custom_bindings.h"
-#include "chrome/renderer/extensions/extension_custom_bindings.h"
-#include "chrome/renderer/extensions/file_browser_handler_custom_bindings.h"
-#include "chrome/renderer/extensions/file_browser_private_custom_bindings.h"
-#include "chrome/renderer/extensions/i18n_custom_bindings.h"
-#include "chrome/renderer/extensions/page_actions_custom_bindings.h"
-#include "chrome/renderer/extensions/page_capture_custom_bindings.h"
-#include "chrome/renderer/extensions/tabs_custom_bindings.h"
-#include "chrome/renderer/extensions/tts_custom_bindings.h"
-#include "chrome/renderer/extensions/web_request_custom_bindings.h"
-
using content::RenderThread;
using extensions::ChromePrivateCustomBindings;
using extensions::ContextMenusCustomBindings;
using extensions::ExperimentalSocketCustomBindings;
+using extensions::ExtensionAPI;
using extensions::ExtensionCustomBindings;
+using extensions::Feature;
using extensions::FileBrowserHandlerCustomBindings;
using extensions::FileBrowserPrivateCustomBindings;
using extensions::I18NCustomBindings;
@@ -78,19 +79,11 @@ using WebKit::WebScopedUserGesture;
using WebKit::WebVector;
using WebKit::WebView;
-namespace util = extensions::custom_bindings_util;
-
namespace {
static const int64 kInitialExtensionIdleHandlerDelayMs = 5*1000;
static const int64 kMaxExtensionIdleHandlerDelayMs = 5*60*1000;
-ChromeV8Context::ContextType ExtensionGroupToContextType(int extension_group) {
- if (extension_group == EXTENSION_GROUP_CONTENT_SCRIPTS)
- return ChromeV8Context::CONTENT_SCRIPT;
- return ChromeV8Context::OTHER;
-}
-
class ChromeHiddenNativeHandler : public NativeHandler {
public:
ChromeHiddenNativeHandler() {
@@ -125,41 +118,6 @@ class PrintNativeHandler : public NativeHandler {
}
};
-class ContextInfoNativeHandler : public NativeHandler {
- public:
- explicit ContextInfoNativeHandler(ExtensionDispatcher* extension_dispatcher,
- bool is_bindings_allowed,
- WebKit::WebFrame* frame,
- int world_id)
- : extension_dispatcher_(extension_dispatcher),
- is_bindings_allowed_(is_bindings_allowed),
- frame_(frame),
- world_id_(world_id) {
- RouteFunction("IsBindingsAllowed",
- base::Bind(&ContextInfoNativeHandler::IsBindingsAllowed,
- base::Unretained(this)));
- RouteFunction("IsAPIAllowed",
- base::Bind(&ContextInfoNativeHandler::IsAPIAllowed,
- base::Unretained(this)));
- }
-
- v8::Handle<v8::Value> IsBindingsAllowed(const v8::Arguments& args) {
- return v8::Boolean::New(is_bindings_allowed_);
- }
-
- v8::Handle<v8::Value> IsAPIAllowed(const v8::Arguments& args) {
- std::string custom_api_name = *v8::String::AsciiValue(args[0]->ToString());
- return v8::Boolean::New(extension_dispatcher_->AllowCustomAPI(
- frame_, custom_api_name, world_id_));
- }
-
- private:
- ExtensionDispatcher* extension_dispatcher_;
- bool is_bindings_allowed_;
- WebKit::WebFrame* frame_;
- int world_id_;
-};
-
}
ExtensionDispatcher::ExtensionDispatcher()
@@ -197,7 +155,6 @@ bool ExtensionDispatcher::OnControlMessageReceived(
IPC_MESSAGE_HANDLER(ExtensionMsg_SetScriptingWhitelist,
OnSetScriptingWhitelist)
IPC_MESSAGE_HANDLER(ExtensionMsg_ActivateExtension, OnActivateExtension)
- IPC_MESSAGE_HANDLER(ExtensionMsg_ActivateApplication, OnActivateApplication)
IPC_MESSAGE_HANDLER(ExtensionMsg_UpdatePermissions, OnUpdatePermissions)
IPC_MESSAGE_HANDLER(ExtensionMsg_UpdateUserScripts, OnUpdateUserScripts)
IPC_MESSAGE_HANDLER(ExtensionMsg_UsingWebRequestAPI, OnUsingWebRequestAPI)
@@ -347,12 +304,6 @@ void ExtensionDispatcher::OnSetScriptingWhitelist(
Extension::SetScriptingWhitelist(extension_ids);
}
-bool ExtensionDispatcher::IsApplicationActive(
- const std::string& extension_id) const {
- return active_application_ids_.find(extension_id) !=
- active_application_ids_.end();
-}
-
bool ExtensionDispatcher::IsExtensionActive(
const std::string& extension_id) const {
return active_extension_ids_.find(extension_id) !=
@@ -387,34 +338,8 @@ bool ExtensionDispatcher::AllowScriptExtension(
return true;
}
-bool ExtensionDispatcher::AllowCustomAPI(
- WebFrame* frame,
- const std::string& custom_binding_api_name,
- int world_id) {
- std::string extension_id = GetExtensionID(frame, world_id);
- if (IsTestExtensionId(extension_id))
- return true;
- const Extension* extension = extensions_.GetByID(extension_id);
- if (!extension) {
- // This can happen when a resource is blocked due to CSP; a valid
- // chrome-extension:// URL is navigated to, so it passes the initial
- // checks, but the URL gets changed to "chrome-extension://invalid"
- // afterwards (see chrome_content_renderer_client.cc). An extension
- // page still gets loaded, just for the extension with ID "invalid",
- // which of course isn't found so GetById extension will be NULL.
- //
- // Reference: http://crbug.com/111614.
- CHECK_EQ("invalid", extension_id);
- return false;
- }
- return util::AllowAPIInjection(
- custom_binding_api_name, *extension, this);
-}
-
void ExtensionDispatcher::RegisterNativeHandlers(ModuleSystem* module_system,
ChromeV8Context* context) {
- module_system->RegisterNativeHandler("app",
- scoped_ptr<NativeHandler>(new AppBindings(this, context)));
module_system->RegisterNativeHandler("webstore",
scoped_ptr<NativeHandler>(new WebstoreBindings(this, context)));
module_system->RegisterNativeHandler("event_bindings",
@@ -425,6 +350,8 @@ void ExtensionDispatcher::RegisterNativeHandlers(ModuleSystem* module_system,
scoped_ptr<NativeHandler>(SchemaGeneratedBindings::Get(this)));
// Custom bindings.
+ module_system->RegisterNativeHandler("app",
+ scoped_ptr<NativeHandler>(new AppBindings(this, context)));
module_system->RegisterNativeHandler("chrome_private",
scoped_ptr<NativeHandler>(
new ChromePrivateCustomBindings(this)));
@@ -455,7 +382,6 @@ void ExtensionDispatcher::RegisterNativeHandlers(ModuleSystem* module_system,
}
void ExtensionDispatcher::PopulateSourceMap() {
- source_map_.RegisterSource("app", IDR_APP_BINDINGS_JS);
source_map_.RegisterSource("webstore", IDR_WEBSTORE_BINDINGS_JS);
source_map_.RegisterSource("event_bindings", IDR_EVENT_BINDINGS_JS);
source_map_.RegisterSource("miscellaneous_bindings",
@@ -464,9 +390,9 @@ void ExtensionDispatcher::PopulateSourceMap() {
IDR_SCHEMA_GENERATED_BINDINGS_JS);
source_map_.RegisterSource("json_schema", IDR_JSON_SCHEMA_JS);
source_map_.RegisterSource("apitest", IDR_EXTENSION_APITEST_JS);
- source_map_.RegisterSource("setup_bindings", IDR_SETUP_BINDINGS_JS);
- // Custom bindings.
+ // Custom bindings.
+ source_map_.RegisterSource("app", IDR_APP_CUSTOM_BINDINGS_JS);
source_map_.RegisterSource("browserAction",
IDR_BROWSER_ACTION_CUSTOM_BINDINGS_JS);
source_map_.RegisterSource("chromePrivate",
@@ -509,36 +435,37 @@ void ExtensionDispatcher::DidCreateScriptContext(
extension_group = g_hack_extension_group;
std::string extension_id = GetExtensionID(frame, world_id);
+
+ const Extension* extension = extensions_.GetByID(extension_id);
+ if (!extension && !extension_id.empty() && !IsTestExtensionId(extension_id)) {
+ // There are conditions where despite a context being associated with an
+ // extension, no extension actually gets found. Ignore "invalid" because
+ // CSP blocks extension page loading by switching the extension ID to
+ // "invalid". This isn't interesting.
+ if (extension_id != "invalid") {
+ LOG(ERROR) << "Extension \"" << extension_id << "\" not found";
+ RenderThread::Get()->RecordUserMetrics("ExtensionNotFound_ED");
+ }
+ }
+
+ ExtensionURLInfo url_info(frame->document().securityOrigin(),
+ UserScriptSlave::GetDataSourceURLForFrame(frame));
+
+ Feature::Context context_type =
+ ClassifyJavaScriptContext(extension_id, extension_group, url_info);
+
ChromeV8Context* context =
- new ChromeV8Context(
- v8_context,
- frame,
- extension_id,
- ExtensionGroupToContextType(extension_group));
+ new ChromeV8Context(v8_context, frame, extension_id, context_type);
v8_context_set_.Add(context);
scoped_ptr<ModuleSystem> module_system(new ModuleSystem(&source_map_));
RegisterNativeHandlers(module_system.get(), context);
- bool is_bindings_allowed =
- IsTestExtensionId(extension_id) ||
- context->context_type() == ChromeV8Context::CONTENT_SCRIPT ||
- extensions_.ExtensionBindingsAllowed(ExtensionURLInfo(
- frame->document().securityOrigin(),
- UserScriptSlave::GetDataSourceURLForFrame(frame)));
-
module_system->RegisterNativeHandler("chrome_hidden",
scoped_ptr<NativeHandler>(new ChromeHiddenNativeHandler()));
- module_system->RegisterNativeHandler("context_info",
- scoped_ptr<NativeHandler>(new ContextInfoNativeHandler(
- this,
- is_bindings_allowed,
- frame,
- world_id)));
module_system->RegisterNativeHandler("print",
scoped_ptr<NativeHandler>(new PrintNativeHandler()));
- const Extension* extension = extensions_.GetByID(context->extension_id());
int manifest_version = 1;
if (extension)
manifest_version = extension->manifest_version();
@@ -551,11 +478,46 @@ void ExtensionDispatcher::DidCreateScriptContext(
if (global->Get(chrome_string)->IsUndefined())
global->Set(chrome_string, v8::Object::New());
}
- module_system->Require("app");
- module_system->Require("webstore");
- if (is_bindings_allowed) {
- module_system->Require("setup_bindings");
+
+ // Loading JavaScript is expensive, so only run the full API bindings
+ // generation mechanisms in extension pages (NOT all web pages).
+ switch (context_type) {
+ case Feature::UNSPECIFIED_CONTEXT:
+ case Feature::WEB_PAGE_CONTEXT:
+ break;
+
+ case Feature::PRIVILEGED_CONTEXT:
+ case Feature::UNPRIVILEGED_CONTEXT:
+ case Feature::CONTENT_SCRIPT_CONTEXT:
+ module_system->Require("json_schema");
+ module_system->Require("event_bindings");
+ module_system->Require("miscellaneous_bindings");
+ module_system->Require("schema_generated_bindings");
+ module_system->Require("apitest");
+ break;
+ }
+
+ scoped_ptr<std::set<std::string> > apis =
+ ExtensionAPI::GetInstance()->GetAPIsForContext(
+ context_type, extension, url_info.url());
+
+ // TODO(kalman): include this in the APIs returned from GetAPIsForContext.
+ apis->insert("webstore");
+
+ // TODO(kalman): this is probably the most unfortunate thing I've ever had
+ // to write. We really need to factor things differently to delete the
+ // concept of a test extension ID.
+ if (IsTestExtensionId(extension_id)) {
+ module_system->Require("miscellaneous_bindings");
+ module_system->Require("schema_generated_bindings");
+ apis->insert("extension");
}
+
+ for (std::set<std::string>::iterator i = apis->begin(); i != apis->end();
+ ++i) {
+ module_system->Require(*i);
+ }
+
module_system->set_natives_enabled(false);
context->set_module_system(module_system.Pass());
@@ -595,6 +557,7 @@ void ExtensionDispatcher::WillReleaseScriptContext(
}
void ExtensionDispatcher::SetTestExtensionId(const std::string& id) {
+ CHECK(!id.empty());
test_extension_id_ = id;
}
@@ -602,11 +565,6 @@ bool ExtensionDispatcher::IsTestExtensionId(const std::string& id) {
return !test_extension_id_.empty() && id == test_extension_id_;
}
-void ExtensionDispatcher::OnActivateApplication(
- const std::string& extension_id) {
- active_application_ids_.insert(extension_id);
-}
-
void ExtensionDispatcher::OnActivateExtension(
const std::string& extension_id) {
active_extension_ids_.insert(extension_id);
@@ -734,3 +692,22 @@ void ExtensionDispatcher::OnShouldClose(const std::string& extension_id,
RenderThread::Get()->Send(
new ExtensionHostMsg_ShouldCloseAck(extension_id, sequence_id));
}
+
+Feature::Context ExtensionDispatcher::ClassifyJavaScriptContext(
+ const std::string& extension_id,
+ int extension_group,
+ const ExtensionURLInfo& url_info) {
+ if (extension_group == EXTENSION_GROUP_CONTENT_SCRIPTS)
+ return Feature::CONTENT_SCRIPT_CONTEXT;
+
+ if (IsExtensionActive(extension_id))
+ return Feature::PRIVILEGED_CONTEXT;
+
+ if (extensions_.ExtensionBindingsAllowed(url_info))
+ return Feature::UNPRIVILEGED_CONTEXT;
+
+ if (url_info.url().is_valid())
+ return Feature::WEB_PAGE_CONTEXT;
+
+ return Feature::UNSPECIFIED_CONTEXT;
+}
diff --git a/chrome/renderer/extensions/extension_dispatcher.h b/chrome/renderer/extensions/extension_dispatcher.h
index b1dfb40..3a0d2c1 100644
--- a/chrome/renderer/extensions/extension_dispatcher.h
+++ b/chrome/renderer/extensions/extension_dispatcher.h
@@ -14,6 +14,8 @@
#include "base/timer.h"
#include "content/public/renderer/render_process_observer.h"
#include "chrome/common/extensions/extension_set.h"
+#include "chrome/common/extensions/feature.h"
+#include "chrome/renderer/extensions/chrome_v8_context.h"
#include "chrome/renderer/extensions/chrome_v8_context_set.h"
#include "chrome/renderer/resource_bundle_source_map.h"
#include "v8/include/v8.h"
@@ -54,13 +56,13 @@ class ExtensionDispatcher : public content::RenderProcessObserver {
}
UserScriptSlave* user_script_slave() { return user_script_slave_.get(); }
- bool IsApplicationActive(const std::string& extension_id) const;
bool IsExtensionActive(const std::string& extension_id) const;
- // Whether or not we should set up custom bindings for this api.
- bool AllowCustomAPI(WebKit::WebFrame* frame,
- const std::string& custom_binding_api_name,
- int world_id);
+ // Finds the extension ID for the JavaScript context associated with the
+ // specified |frame| and isolated world. If |world_id| is zero, finds the
+ // extension ID associated with the main world's JavaScript context. If the
+ // JavaScript context isn't from an extension, returns empty string.
+ std::string GetExtensionID(WebKit::WebFrame* frame, int world_id);
// See WebKit::WebPermissionClient::allowScriptExtension
// TODO(koz): Remove once WebKit no longer calls this.
@@ -118,7 +120,6 @@ class ExtensionDispatcher : public content::RenderProcessObserver {
const Extension::ScriptingWhitelist& extension_ids);
void OnPageActionsUpdated(const std::string& extension_id,
const std::vector<std::string>& page_actions);
- void OnActivateApplication(const std::string& extension_id);
void OnActivateExtension(const std::string& extension_id);
void OnUpdatePermissions(int reason_id,
const std::string& extension_id,
@@ -151,9 +152,11 @@ class ExtensionDispatcher : public content::RenderProcessObserver {
// Inserts static source code into |source_map_|.
void PopulateSourceMap();
- // Finds the extension ID for the current context. This is determined from
- // |world_id| if it's non-zero, or the URL in |frame| if it is.
- std::string GetExtensionID(WebKit::WebFrame* frame, int world_id);
+ // Returns the Feature::Context type of context for a JavaScript context.
+ extensions::Feature::Context ClassifyJavaScriptContext(
+ const std::string& extension_id,
+ int extension_group,
+ const ExtensionURLInfo& url_info);
// True if this renderer is running extensions.
bool is_extension_process_;
@@ -179,12 +182,9 @@ class ExtensionDispatcher : public content::RenderProcessObserver {
// All declared function names.
std::set<std::string> function_names_;
- // The extensions that are active in this process.
+ // The extensions and apps that are active in this process.
std::set<std::string> active_extension_ids_;
- // The applications that are active in this process.
- std::set<std::string> active_application_ids_;
-
// True once WebKit has been initialized (and it is therefore safe to poke).
bool is_webkit_initialized_;
diff --git a/chrome/renderer/extensions/schema_generated_bindings.cc b/chrome/renderer/extensions/schema_generated_bindings.cc
index eda15d8..257f3f9 100644
--- a/chrome/renderer/extensions/schema_generated_bindings.cc
+++ b/chrome/renderer/extensions/schema_generated_bindings.cc
@@ -31,6 +31,7 @@
#include "chrome/renderer/extensions/extension_dispatcher.h"
#include "chrome/renderer/extensions/miscellaneous_bindings.h"
#include "chrome/renderer/extensions/user_script_slave.h"
+#include "content/public/renderer/render_thread.h"
#include "content/public/renderer/render_view.h"
#include "content/public/renderer/v8_value_converter.h"
#include "grit/common_resources.h"
@@ -44,8 +45,10 @@
#include "v8/include/v8.h"
#include "webkit/glue/webkit_glue.h"
+using content::RenderThread;
using content::V8ValueConverter;
using extensions::ExtensionAPI;
+using extensions::Feature;
using WebKit::WebFrame;
using WebKit::WebSecurityOrigin;
@@ -118,30 +121,37 @@ class ExtensionImpl : public ChromeV8Extension {
ChromeV8Context* v8_context = dispatcher->v8_context_set().GetCurrent();
CHECK(v8_context);
- std::string extension_id = v8_context->extension_id();
- ExtensionAPI::SchemaMap schemas;
- ExtensionAPI::GetSchemasFilter filter =
- dispatcher->is_extension_process() ?
- ExtensionAPI::ALL : ExtensionAPI::ONLY_UNPRIVILEGED;
+ // TODO(kalman): This is being calculated twice, first in
+ // ExtensionDispatcher then again here. It might as well be a property of
+ // ChromeV8Context, however, this would require making ChromeV8Context take
+ // an Extension rather than an extension ID. In itself this is fine,
+ // however it does not play correctly with the "IsTestExtensionId" checks.
+ // We need to remove that first.
+ scoped_ptr<std::set<std::string> > apis;
+ const std::string& extension_id = v8_context->extension_id();
if (dispatcher->IsTestExtensionId(extension_id)) {
- ExtensionAPI::GetInstance()->GetDefaultSchemas(filter, &schemas);
+ apis.reset(new std::set<std::string>());
+ // The minimal set of APIs that tests need.
+ apis->insert("extension");
} else {
- const ::Extension* extension =
- dispatcher->extensions()->GetByID(extension_id);
- CHECK(extension) << extension_id << " not found";
- ExtensionAPI::GetInstance()->GetSchemasForExtension(
- *extension, filter, &schemas);
+ apis = ExtensionAPI::GetInstance()->GetAPIsForContext(
+ v8_context->context_type(),
+ dispatcher->extensions()->GetByID(extension_id),
+ UserScriptSlave::GetDataSourceURLForFrame(v8_context->web_frame()));
}
v8::Persistent<v8::Context> context(v8::Context::New());
v8::Context::Scope context_scope(context);
- v8::Handle<v8::Array> api(v8::Array::New(schemas.size()));
+ v8::Handle<v8::Array> api(v8::Array::New(apis->size()));
size_t api_index = 0;
- for (ExtensionAPI::SchemaMap::iterator it = schemas.begin();
- it != schemas.end(); ++it) {
- std::string api_name = it->first;
- api->Set(api_index, GetV8SchemaForAPI(self, context, api_name));
+ for (std::set<std::string>::iterator i = apis->begin(); i != apis->end();
+ ++i) {
+ // TODO(kalman): this caching is actually useless now, because
+ // SchemaGeneratedBindings is per-context not per-process. We should
+ // (e.g.) hang a SchemaRegistry off ExtensionDispatcher (which maintains
+ // a *single* v8::Context rather than multiple ones as here).
+ api->Set(api_index, GetV8SchemaForAPI(self, context, *i));
++api_index;
}
@@ -323,6 +333,7 @@ class ExtensionImpl : public ChromeV8Extension {
namespace extensions {
+// static
ChromeV8Extension* SchemaGeneratedBindings::Get(
ExtensionDispatcher* extension_dispatcher) {
return new ExtensionImpl(extension_dispatcher);
diff --git a/chrome/renderer/renderer_resources.grd b/chrome/renderer/renderer_resources.grd
index a0df32c..32c9b9f 100644
--- a/chrome/renderer/renderer_resources.grd
+++ b/chrome/renderer/renderer_resources.grd
@@ -11,7 +11,6 @@ without changes to the corresponding grd file. fb9 -->
</outputs>
<release seq="1">
<includes>
- <include name="IDR_APP_BINDINGS_JS" file="resources\extensions\app.js" type="BINDATA" />
<include name="IDR_BLOCKED_PLUGIN_HTML" file="resources\blocked_plugin.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_CLICK_TO_PLAY_PLUGIN_HTML" file="resources\click_to_play_plugin.html" flattenhtml="true" type="BINDATA" />
<include name="IDR_DISABLED_PLUGIN_HTML" file="resources\disabled_plugin.html" flattenhtml="true" type="BINDATA" />
@@ -25,11 +24,10 @@ without changes to the corresponding grd file. fb9 -->
<include name="IDR_PLATFORM_APP_CSS" file="resources\extensions\platform_app.css" type="BINDATA" />
<include name="IDR_SAD_PLUGIN" file="resources\sadplugin.png" type="BINDATA" />
<include name="IDR_SCHEMA_GENERATED_BINDINGS_JS" file="resources\extensions\schema_generated_bindings.js" type="BINDATA" />
- <include name="IDR_SETUP_BINDINGS_JS" file="resources\extensions\setup_bindings.js" type="BINDATA" />
<include name="IDR_WEBSTORE_BINDINGS_JS" file="resources\extensions\webstore.js" type="BINDATA" />
<!-- Custom bindings for extension APIs. -->
- <include name="IDR_I18N_CUSTOM_BINDINGS_JS" file="resources\extensions\i18n_custom_bindings.js" type="BINDATA" />
+ <include name="IDR_APP_CUSTOM_BINDINGS_JS" file="resources\extensions\app_custom_bindings.js" type="BINDATA" />
<include name="IDR_BROWSER_ACTION_CUSTOM_BINDINGS_JS" file="resources\extensions\browser_action_custom_bindings.js" type="BINDATA" />
<include name="IDR_CHROME_PRIVATE_CUSTOM_BINDINGS_JS" file="resources\extensions\chrome_private_custom_bindings.js" type="BINDATA" />
<include name="IDR_CONTENT_SETTINGS_CUSTOM_BINDINGS_JS" file="resources\extensions\content_settings_custom_bindings.js" type="BINDATA" />
@@ -40,6 +38,7 @@ without changes to the corresponding grd file. fb9 -->
<include name="IDR_EXTENSION_CUSTOM_BINDINGS_JS" file="resources\extensions\extension_custom_bindings.js" type="BINDATA" />
<include name="IDR_FILE_BROWSER_HANDLER_CUSTOM_BINDINGS_JS" file="resources\extensions\file_browser_handler_custom_bindings.js" type="BINDATA" />
<include name="IDR_FILE_BROWSER_PRIVATE_CUSTOM_BINDINGS_JS" file="resources\extensions\file_browser_private_custom_bindings.js" type="BINDATA" />
+ <include name="IDR_I18N_CUSTOM_BINDINGS_JS" file="resources\extensions\i18n_custom_bindings.js" type="BINDATA" />
<include name="IDR_INPUT_IME_CUSTOM_BINDINGS_JS" file="resources\extensions\input.ime_custom_bindings.js" type="BINDATA" />
<include name="IDR_OMNIBOX_CUSTOM_BINDINGS_JS" file="resources\extensions\omnibox_custom_bindings.js" type="BINDATA" />
<include name="IDR_PAGE_ACTIONS_CUSTOM_BINDINGS_JS" file="resources\extensions\page_actions_custom_bindings.js" type="BINDATA" />
diff --git a/chrome/renderer/resource_bundle_source_map.cc b/chrome/renderer/resource_bundle_source_map.cc
index 2c06b7b..5a42582 100644
--- a/chrome/renderer/resource_bundle_source_map.cc
+++ b/chrome/renderer/resource_bundle_source_map.cc
@@ -28,7 +28,7 @@ v8::Handle<v8::Value> ResourceBundleSourceMap::GetSource(
}
bool ResourceBundleSourceMap::Contains(const std::string& name) {
- return resource_id_map_.count(name) > 0;
+ return !!resource_id_map_.count(name);
}
v8::Handle<v8::String> ResourceBundleSourceMap::ConvertString(
diff --git a/chrome/renderer/resources/extensions/app.js b/chrome/renderer/resources/extensions/app.js
deleted file mode 100644
index 7337d86..0000000
--- a/chrome/renderer/resources/extensions/app.js
+++ /dev/null
@@ -1,41 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
- var natives = requireNative('app');
- var GetIsInstalled = natives.GetIsInstalled;
- var Install = natives.Install;
- var GetDetails = natives.GetDetails;
- var GetDetailsForFrame = natives.GetDetailsForFrame;
- var GetAppNotifyChannel = natives.GetAppNotifyChannel;
-
- var chromeHidden = requireNative('chrome_hidden').GetChromeHidden();
- var callbacks = {};
- var nextCallbackId = 1;
-
- chrome.app = new function() {
- this.__defineGetter__('isInstalled', GetIsInstalled);
- this.install = Install;
- this.getDetails = GetDetails;
- this.getDetailsForFrame = GetDetailsForFrame;
- }();
-
- chrome.appNotifications = new function() {
- this.getChannel = function(clientId, callback) {
- var callbackId = 0;
- if (callback) {
- callbackId = nextCallbackId++;
- callbacks[callbackId] = callback;
- }
- GetAppNotifyChannel(clientId, callbackId);
- };
- }();
-
- chromeHidden.app = {};
- chromeHidden.app.onGetAppNotifyChannelResponse =
- function(channelId, error, callbackId) {
- if (callbackId) {
- callbacks[callbackId](channelId, error);
- delete callbacks[callbackId];
- }
- };
diff --git a/chrome/renderer/resources/extensions/app_custom_bindings.js b/chrome/renderer/resources/extensions/app_custom_bindings.js
new file mode 100644
index 0000000..9cae9d4
--- /dev/null
+++ b/chrome/renderer/resources/extensions/app_custom_bindings.js
@@ -0,0 +1,52 @@
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Custom bindings for the app API.
+
+var appNatives = requireNative('app');
+var chromeHidden = requireNative('chrome_hidden').GetChromeHidden();
+
+chrome.app = {
+ getIsInstalled: appNatives.GetIsInstalled,
+ install: appNatives.Install,
+ getDetails: appNatives.GetDetails,
+ getDetailsForFrame: appNatives.GetDetailsForFrame
+};
+
+// Tricky; "getIsInstalled" is actually exposed as the getter "isInstalled",
+// but we don't have a way to express this in the schema JSON (nor is it
+// worth it for this one special case).
+//
+// So, define it manually, and let the getIsInstalled function act as its
+// documentation.
+chrome.app.__defineGetter__('isInstalled', appNatives.GetIsInstalled);
+
+// Called by app_bindings.cc.
+chromeHidden.app = {
+ onGetAppNotifyChannelResponse: function(channelId, error, callbackId) {
+ if (callbackId) {
+ callbacks[callbackId](channelId, error);
+ delete callbacks[callbackId];
+ }
+ }
+};
+
+// appNotification stuff.
+//
+// TODO(kalman): move this stuff to its own custom bindings.
+// It will be bit tricky since I'll need to look into why there are
+// permissions defined for app notifications, yet this always sets it up?
+var callbacks = {};
+var nextCallbackId = 1;
+
+chrome.appNotifications = {
+ getChannel: function getChannel(clientId, callback) {
+ var callbackId = 0;
+ if (callback) {
+ callbackId = nextCallbackId++;
+ callbacks[callbackId] = callback;
+ }
+ appNatives.GetAppNotifyChannel(clientId, callbackId);
+ }
+};
diff --git a/chrome/renderer/resources/extensions/schema_generated_bindings.js b/chrome/renderer/resources/extensions/schema_generated_bindings.js
index ab11923..217414c 100644
--- a/chrome/renderer/resources/extensions/schema_generated_bindings.js
+++ b/chrome/renderer/resources/extensions/schema_generated_bindings.js
@@ -531,6 +531,11 @@
var platform = getPlatform();
apiDefinitions.forEach(function(apiDef) {
+ // TODO(kalman): Remove this, or refactor schema_generated_bindings.js so
+ // that it isn't necessary. For now, chrome.app is entirely handwritten.
+ if (apiDef.namespace === 'app')
+ return;
+
if (!isSchemaNodeSupported(apiDef, platform, manifestVersion))
return;
diff --git a/chrome/renderer/resources/extensions/setup_bindings.js b/chrome/renderer/resources/extensions/setup_bindings.js
deleted file mode 100644
index ba002d9..0000000
--- a/chrome/renderer/resources/extensions/setup_bindings.js
+++ /dev/null
@@ -1,16 +0,0 @@
-// Copyright (c) 2012 The Chromium Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-var contextInfo = requireNative('context_info');
-var sgb = requireNative('schema_generated_bindings');
-
-require('miscellaneous_bindings');
-require('schema_generated_bindings');
-require('apitest');
-
-// Load the custom bindings for each API.
-sgb.GetExtensionAPIDefinition().forEach(function(apiDef) {
- if (contextInfo.IsAPIAllowed(apiDef.namespace))
- require(apiDef.namespace);
-});
diff --git a/chrome/test/data/extensions/api_test/content_scripts/extension_iframe/iframe.js b/chrome/test/data/extensions/api_test/content_scripts/extension_iframe/iframe.js
index 3e37a3a..572f280 100644
--- a/chrome/test/data/extensions/api_test/content_scripts/extension_iframe/iframe.js
+++ b/chrome/test/data/extensions/api_test/content_scripts/extension_iframe/iframe.js
@@ -28,11 +28,15 @@ if (chrome.storage) {
success = false;
}
-// Parts of chrome.extension and chrome.tabs (which get included because it's
-// a dependency of chrome.extension) are unavailable.
-if (!runsWithException(function() { return chrome.extension.getViews; }))
+// Ditto chrome.tabs, though it's special because it's a dependency of the
+// partially unprivileged chrome.extension.
+if (chrome.tabs) {
+ console.log('Error: chrome.tabs exists, it shouldn\'t.');
success = false;
-if (!runsWithException(function() { return chrome.tabs.create; }))
+}
+
+// Parts of chrome.extension are unavailable.
+if (!runsWithException(function() { return chrome.extension.getViews; }))
success = false;
chrome.extension.sendRequest({success: success});
diff --git a/chrome/test/data/extensions/api_test/stubs/content_script.js b/chrome/test/data/extensions/api_test/stubs/content_script.js
index 79e491c..3eacb11 100644
--- a/chrome/test/data/extensions/api_test/stubs/content_script.js
+++ b/chrome/test/data/extensions/api_test/stubs/content_script.js
@@ -1,4 +1,4 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
@@ -25,7 +25,7 @@ chrome.extension.sendRequest("getApi", function(apis) {
return;
module[section].forEach(function(entry) {
var path = namespace + "." + entry.name;
- if (entry.unprivileged) {
+ if (module.unprivileged || entry.unprivileged) {
unprivilegedPaths.push(path);
} else {
privilegedPaths.push(path);
@@ -36,7 +36,7 @@ chrome.extension.sendRequest("getApi", function(apis) {
if (module.properties) {
for (var propName in module.properties) {
var path = namespace + "." + propName;
- if (module.properties[propName].unprivileged) {
+ if (module.unprivileged || module.properties[propName].unprivileged) {
unprivilegedPaths.push(path);
} else {
privilegedPaths.push(path);
@@ -69,7 +69,7 @@ function testPath(path, expectError) {
if (typeof(module) == "undefined")
return true;
} else {
- // This is the last component - we expect it to either be defined or
+ // This is the last component - we expect it to either be undefined or
// to throw an error on access.
try {
if (typeof(module[parts[i]]) == "undefined" &&