summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorakalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-09 07:51:29 +0000
committerakalin@chromium.org <akalin@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-03-09 07:51:29 +0000
commitc7f74e7ca7e2b2428fb7434b0ef0b7a9b4bfbff8 (patch)
treed69b0da7ab33542edaae9788d8e7d07ca13c98b6
parent9b83ab913c7a8574d5b50b9113df93cc1fcb7083 (diff)
downloadchromium_src-c7f74e7ca7e2b2428fb7434b0ef0b7a9b4bfbff8.zip
chromium_src-c7f74e7ca7e2b2428fb7434b0ef0b7a9b4bfbff8.tar.gz
chromium_src-c7f74e7ca7e2b2428fb7434b0ef0b7a9b4bfbff8.tar.bz2
Revert 125811 - Convert app_bindings.js to the schema_generated_bindings.js infrastructure.
This involves opening up *all* custom bindings to web pages, where access is controlled content-script style using a URL-matches property in the API schema. BUG=104100,117282 TEST=unit_tests,browser_tests Review URL: http://codereview.chromium.org/9460002 TBR=kalman@chromium.org Review URL: https://chromiumcodereview.appspot.com/9653022 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@125813 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/browser/renderer_host/chrome_render_view_host_observer.cc23
-rw-r--r--chrome/chrome_renderer.gypi4
-rw-r--r--chrome/common/common_resources.grd1
-rw-r--r--chrome/common/extensions/api/app.json70
-rw-r--r--chrome/common/extensions/api/extension_api.cc169
-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.h8
-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.cc167
-rw-r--r--chrome/renderer/extensions/extension_dispatcher.h26
-rw-r--r--chrome/renderer/extensions/schema_generated_bindings.cc35
-rw-r--r--chrome/renderer/renderer_resources.grd4
-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.js56
-rw-r--r--chrome/renderer/resources/extensions/setup_bindings.js22
-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
30 files changed, 514 insertions, 565 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 67a9acb..91da264 100644
--- a/chrome/browser/renderer_host/chrome_render_view_host_observer.cc
+++ b/chrome/browser/renderer_host/chrome_render_view_host_observer.cc
@@ -104,6 +104,7 @@ 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
@@ -126,21 +127,13 @@ void ChromeRenderViewHostObserver::InitRenderViewForExtensions() {
}
}
- 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();
+ 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()));
}
}
diff --git a/chrome/chrome_renderer.gypi b/chrome/chrome_renderer.gypi
index 89422f1..dcd2806 100644
--- a/chrome/chrome_renderer.gypi
+++ b/chrome/chrome_renderer.gypi
@@ -74,6 +74,8 @@
'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',
@@ -128,7 +130,7 @@
'renderer/resource_bundle_source_map.cc',
'renderer/resource_bundle_source_map.h',
'renderer/resources/extensions/apitest.js',
- 'renderer/resources/extensions/app_custom_bindings.js',
+ 'renderer/resources/extensions/app.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',
diff --git a/chrome/common/common_resources.grd b/chrome/common/common_resources.grd
index e556928..253cb1a 100644
--- a/chrome/common/common_resources.grd
+++ b/chrome/common/common_resources.grd
@@ -10,7 +10,6 @@
<release seq="1">
<includes>
<include name="IDR_EXTENSION_MANIFEST_FEATURES" file="extensions\api\_manifest_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
deleted file mode 100644
index 0e813e6..0000000
--- a/chrome/common/extensions/api/app.json
+++ /dev/null
@@ -1,70 +0,0 @@
-[
- {
- "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 ade7ce6..eeece57 100644
--- a/chrome/common/extensions/api/extension_api.cc
+++ b/chrome/common/extensions/api/extension_api.cc
@@ -15,7 +15,6 @@
#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"
@@ -23,6 +22,22 @@ 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,
@@ -80,7 +95,6 @@ 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,
@@ -164,27 +178,6 @@ 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() {
@@ -264,109 +257,59 @@ const base::DictionaryValue* ExtensionAPI::GetSchema(
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) 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:
- // Availability is determined by the permissions of the extension
- // (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::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);
}
-void ExtensionAPI::ResolveDependencies(std::set<std::string>* out) const {
+void ExtensionAPI::ResolveDependencies(SchemaMap* 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);
+ for (SchemaMap::const_iterator i = out->begin(); i != out->end(); ++i)
+ GetMissingDependencies(*i->second, *out, &missing_dependencies);
while (missing_dependencies.size()) {
- std::string next = *missing_dependencies.begin();
- missing_dependencies.erase(next);
- out->insert(next);
- GetMissingDependencies(next, *out, &missing_dependencies);
+ 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);
}
}
-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::GetDefaultSchemas(GetSchemasFilter filter,
+ SchemaMap* out) const {
+ scoped_refptr<ExtensionPermissionSet> default_permissions(
+ new ExtensionPermissionSet());
+ GetSchemasForPermissions(*default_permissions, filter, out);
+ ResolveDependencies(out);
}
-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);
+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::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);
- }
+bool ExtensionAPI::IsWholeAPIPrivileged(const std::string& api_name) const {
+ return !completely_unprivileged_apis_.count(api_name) &&
+ !partially_unprivileged_apis_.count(api_name);
}
} // namespace extensions
diff --git a/chrome/common/extensions/api/extension_api.h b/chrome/common/extensions/api/extension_api.h
index 6e2c604..25ac679 100644
--- a/chrome/common/extensions/api/extension_api.h
+++ b/chrome/common/extensions/api/extension_api.h
@@ -12,11 +12,8 @@
#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;
@@ -24,7 +21,6 @@ class ListValue;
class Value;
}
-class GURL;
class Extension;
class ExtensionPermissionSet;
@@ -33,6 +29,18 @@ 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();
@@ -42,17 +50,26 @@ 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 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;
+ // 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;
private:
friend struct DefaultSingletonTraits<ExtensionAPI>;
@@ -76,34 +93,18 @@ class ExtensionAPI {
const std::string& child_kind,
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) 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 dependent schemas to |out| as determined by the "dependencies"
// property.
- 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;
+ void ResolveDependencies(SchemaMap* 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.
@@ -112,9 +113,6 @@ 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 3f4a0af..70982f7 100644
--- a/chrome/common/extensions/api/extension_api_unittest.cc
+++ b/chrome/common/extensions/api/extension_api_unittest.cc
@@ -13,10 +13,7 @@
#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();
@@ -36,8 +33,6 @@ 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"));
@@ -45,18 +40,34 @@ TEST(ExtensionAPI, IsPrivileged) {
EXPECT_FALSE(extension_api->IsPrivileged("storage.set"));
}
-scoped_refptr<Extension> CreateExtensionWithPermissions(
- const std::set<std::string>& permissions) {
+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.
DictionaryValue manifest;
- manifest.SetString("name", "extension");
+ manifest.SetString("name", "test extension");
manifest.SetString("version", "1.0");
{
- 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());
+ scoped_ptr<ListValue> permissions(new ListValue());
+ permissions->Append(Value::CreateStringValue("ttsEngine"));
+ manifest.Set("permissions", permissions.release());
}
std::string error;
@@ -65,105 +76,8 @@ scoped_refptr<Extension> CreateExtensionWithPermissions(
CHECK(extension.get());
CHECK(error.empty());
- 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"));
+ ExtensionAPI::SchemaMap schemas;
+ ExtensionAPI::GetInstance()->GetSchemasForExtension(
+ *extension, ExtensionAPI::ALL, &schemas);
+ EXPECT_EQ(1u, schemas.count("tts"));
}
-
-} // namespace
diff --git a/chrome/common/extensions/extension_messages.h b/chrome/common/extensions/extension_messages.h
index 7fcd56f..276020e 100644
--- a/chrome/common/extensions/extension_messages.h
+++ b/chrome/common/extensions/extension_messages.h
@@ -193,6 +193,10 @@ 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 f5c8397..18e1fec 100644
--- a/chrome/common/extensions/extension_permission_set.cc
+++ b/chrome/common/extensions/extension_permission_set.cc
@@ -42,7 +42,6 @@ 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",
@@ -617,16 +616,6 @@ 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 0b7c1a3..c219698 100644
--- a/chrome/common/extensions/extension_permission_set.h
+++ b/chrome/common/extensions/extension_permission_set.h
@@ -183,6 +183,8 @@ class ExtensionAPIPermission {
kTypeDefault = kTypeAll - kTypeHostedApp,
};
+ typedef std::set<ID> IDSet;
+
~ExtensionAPIPermission();
// Returns the localized permission message associated with this api.
@@ -392,12 +394,6 @@ 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 b2158e4..aad4d01 100644
--- a/chrome/common/extensions/feature.cc
+++ b/chrome/common/extensions/feature.cc
@@ -21,7 +21,6 @@ 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 2d1a00a..0a95689 100644
--- a/chrome/common/extensions/feature.h
+++ b/chrome/common/extensions/feature.h
@@ -22,21 +22,11 @@ namespace extensions {
class Feature {
public:
// The JavaScript contexts the feature is supported in.
- // TODO(kalman): s/PRIVILEGED/BLESSED_EXTENSION/
enum Context {
UNSPECIFIED_CONTEXT,
-
- // 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,
+ 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.
};
// 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 ea1aa86..0ebaaa9 100644
--- a/chrome/common/extensions/feature_unittest.cc
+++ b/chrome/common/extensions/feature_unittest.cc
@@ -220,14 +220,12 @@ 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(4u, feature->contexts()->size());
+ EXPECT_EQ(3u, 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 a5a902a..34c8047 100644
--- a/chrome/renderer/extensions/app_bindings.cc
+++ b/chrome/renderer/extensions/app_bindings.cc
@@ -55,6 +55,7 @@ const char* kInvalidCallbackIdError = "Invalid callbackId";
} // namespace
+
AppBindings::AppBindings(ExtensionDispatcher* dispatcher,
ChromeV8Context* context)
: ChromeV8Extension(dispatcher),
@@ -71,6 +72,7 @@ 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()
@@ -79,8 +81,9 @@ 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_->IsExtensionActive(extension->id());
+ extension_dispatcher_->IsApplicationActive(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 6d59a19..7db10ed 100644
--- a/chrome/renderer/extensions/chrome_v8_context.cc
+++ b/chrome/renderer/extensions/chrome_v8_context.cc
@@ -15,8 +15,6 @@
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
#include "v8/include/v8.h"
-using extensions::Feature;
-
namespace {
const char kChromeHidden[] = "chromeHidden";
@@ -26,13 +24,11 @@ const char kValidateCallbacks[] = "validateCallbacks";
const char kValidateAPI[] = "validateAPI";
#endif
-std::string GetContextTypeDescription(Feature::Context context_type) {
+std::string GetContextTypeDescription(
+ ChromeV8Context::ContextType context_type) {
switch (context_type) {
- 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";
+ case ChromeV8Context::OTHER: return "other";
+ case ChromeV8Context::CONTENT_SCRIPT: return "content script";
}
NOTREACHED();
return "";
@@ -43,7 +39,7 @@ std::string GetContextTypeDescription(Feature::Context context_type) {
ChromeV8Context::ChromeV8Context(v8::Handle<v8::Context> v8_context,
WebKit::WebFrame* web_frame,
const std::string& extension_id,
- Feature::Context context_type)
+ ChromeV8Context::ContextType 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 e2c8911..3faf9d2 100644
--- a/chrome/renderer/extensions/chrome_v8_context.h
+++ b/chrome/renderer/extensions/chrome_v8_context.h
@@ -9,7 +9,6 @@
#include <string>
#include "base/basictypes.h"
-#include "chrome/common/extensions/feature.h"
#include "chrome/renderer/module_system.h"
#include "v8/include/v8.h"
@@ -28,10 +27,19 @@ 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,
- extensions::Feature::Context context_type);
+ ContextType context_type);
~ChromeV8Context();
v8::Handle<v8::Context> v8_context() const {
@@ -49,7 +57,7 @@ class ChromeV8Context {
web_frame_ = NULL;
}
- extensions::Feature::Context context_type() const {
+ ContextType context_type() const {
return context_type_;
}
@@ -108,7 +116,7 @@ class ChromeV8Context {
std::string extension_id_;
// The type of context.
- extensions::Feature::Context context_type_;
+ ContextType 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 af7b17d..56f4697 100644
--- a/chrome/renderer/extensions/chrome_v8_context_set_unittest.cc
+++ b/chrome/renderer/extensions/chrome_v8_context_set_unittest.cc
@@ -3,7 +3,6 @@
// 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"
@@ -22,11 +21,9 @@ 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,
- extensions::Feature::PRIVILEGED_CONTEXT);
+ ChromeV8Context* context =
+ new ChromeV8Context(
+ v8_context, frame, extension_id, ChromeV8Context::OTHER);
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
new file mode 100644
index 0000000..5de0470b
--- /dev/null
+++ b/chrome/renderer/extensions/custom_bindings_util.cc
@@ -0,0 +1,92 @@
+// 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
new file mode 100644
index 0000000..73d026d
--- /dev/null
+++ b/chrome/renderer/extensions/custom_bindings_util.h
@@ -0,0 +1,44 @@
+// 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 afb45e0..c4895cd 100644
--- a/chrome/renderer/extensions/extension_custom_bindings.cc
+++ b/chrome/renderer/extensions/extension_custom_bindings.cc
@@ -22,6 +22,9 @@
#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 1961a2f..0d12b18 100644
--- a/chrome/renderer/extensions/extension_dispatcher.cc
+++ b/chrome/renderer/extensions/extension_dispatcher.cc
@@ -18,23 +18,12 @@
#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/chrome_private_custom_bindings.h"
-#include "chrome/renderer/extensions/context_menus_custom_bindings.h"
+#include "chrome/renderer/extensions/custom_bindings_util.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"
@@ -44,19 +33,38 @@
#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"
+
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() {
@@ -91,6 +99,41 @@ 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_;
+};
+
}
using namespace extensions;
@@ -140,6 +183,7 @@ 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)
@@ -289,6 +333,12 @@ 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) !=
@@ -323,8 +373,34 @@ 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 (test_extension_id_ == 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 custom_bindings_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",
@@ -335,8 +411,6 @@ 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)));
@@ -367,6 +441,7 @@ 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",
@@ -377,8 +452,7 @@ void ExtensionDispatcher::PopulateSourceMap() {
source_map_.RegisterSource("apitest", IDR_EXTENSION_APITEST_JS);
source_map_.RegisterSource("setup_bindings", IDR_SETUP_BINDINGS_JS);
- // Custom bindings.
- source_map_.RegisterSource("app", IDR_APP_CUSTOM_BINDINGS_JS);
+ // Custom bindings.
source_map_.RegisterSource("browserAction",
IDR_BROWSER_ACTION_CUSTOM_BINDINGS_JS);
source_map_.RegisterSource("chromePrivate",
@@ -421,29 +495,39 @@ void ExtensionDispatcher::DidCreateScriptContext(
extension_group = g_hack_extension_group;
std::string extension_id = GetExtensionID(frame, world_id);
- 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, context_type);
+ new ChromeV8Context(
+ v8_context,
+ frame,
+ extension_id,
+ ExtensionGroupToContextType(extension_group));
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;
- {
- const Extension* extension = extensions_.GetByID(extension_id);
- if (extension)
- manifest_version = extension->manifest_version();
- }
+ if (extension)
+ manifest_version = extension->manifest_version();
module_system->RunString("var chrome; chrome = chrome || {};",
"setup-chrome-object");
@@ -487,7 +571,6 @@ void ExtensionDispatcher::WillReleaseScriptContext(
}
void ExtensionDispatcher::SetTestExtensionId(const std::string& id) {
- CHECK(!id.empty());
test_extension_id_ = id;
}
@@ -495,6 +578,11 @@ 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);
@@ -622,22 +710,3 @@ 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 3a0d2c1..b1dfb40 100644
--- a/chrome/renderer/extensions/extension_dispatcher.h
+++ b/chrome/renderer/extensions/extension_dispatcher.h
@@ -14,8 +14,6 @@
#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"
@@ -56,13 +54,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;
- // 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);
+ // 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);
// See WebKit::WebPermissionClient::allowScriptExtension
// TODO(koz): Remove once WebKit no longer calls this.
@@ -120,6 +118,7 @@ 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,
@@ -152,11 +151,9 @@ class ExtensionDispatcher : public content::RenderProcessObserver {
// Inserts static source code into |source_map_|.
void PopulateSourceMap();
- // 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);
+ // 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);
// True if this renderer is running extensions.
bool is_extension_process_;
@@ -182,9 +179,12 @@ class ExtensionDispatcher : public content::RenderProcessObserver {
// All declared function names.
std::set<std::string> function_names_;
- // The extensions and apps that are active in this process.
+ // The extensions 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 6f6bb33..eda15d8 100644
--- a/chrome/renderer/extensions/schema_generated_bindings.cc
+++ b/chrome/renderer/extensions/schema_generated_bindings.cc
@@ -118,32 +118,30 @@ class ExtensionImpl : public ChromeV8Extension {
ChromeV8Context* v8_context = dispatcher->v8_context_set().GetCurrent();
CHECK(v8_context);
- // TODO(kalman): can we just cache this in the ChromeV8Context instance?
- scoped_ptr<std::set<std::string> > apis;
+ std::string extension_id = v8_context->extension_id();
+ ExtensionAPI::SchemaMap schemas;
+ ExtensionAPI::GetSchemasFilter filter =
+ dispatcher->is_extension_process() ?
+ ExtensionAPI::ALL : ExtensionAPI::ONLY_UNPRIVILEGED;
- const std::string& extension_id = v8_context->extension_id();
if (dispatcher->IsTestExtensionId(extension_id)) {
- apis.reset(new std::set<std::string>());
- // The minimal set of APIs that tests need.
- apis->insert("extension");
+ ExtensionAPI::GetInstance()->GetDefaultSchemas(filter, &schemas);
} else {
- apis = ExtensionAPI::GetInstance()->GetAPIsForContext(
- v8_context->context_type(),
- dispatcher->extensions()->GetByID(extension_id),
- UserScriptSlave::GetDataSourceURLForFrame(v8_context->web_frame()));
+ const ::Extension* extension =
+ dispatcher->extensions()->GetByID(extension_id);
+ CHECK(extension) << extension_id << " not found";
+ ExtensionAPI::GetInstance()->GetSchemasForExtension(
+ *extension, filter, &schemas);
}
v8::Persistent<v8::Context> context(v8::Context::New());
v8::Context::Scope context_scope(context);
- v8::Handle<v8::Array> api(v8::Array::New(apis->size()));
+ v8::Handle<v8::Array> api(v8::Array::New(schemas.size()));
size_t api_index = 0;
- 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));
+ 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));
++api_index;
}
@@ -325,7 +323,6 @@ 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 e2a7484..99cd777 100644
--- a/chrome/renderer/renderer_resources.grd
+++ b/chrome/renderer/renderer_resources.grd
@@ -11,6 +11,7 @@ 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" />
@@ -29,7 +30,7 @@ without changes to the corresponding grd file. fb9 -->
<include name="IDR_WEBSTORE_BINDINGS_JS" file="resources\extensions\webstore.js" type="BINDATA" />
<!-- Custom bindings for extension APIs. -->
- <include name="IDR_APP_CUSTOM_BINDINGS_JS" file="resources\extensions\app_custom_bindings.js" type="BINDATA" />
+ <include name="IDR_I18N_CUSTOM_BINDINGS_JS" file="resources\extensions\i18n_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,7 +41,6 @@ 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 5a42582..2c06b7b 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);
+ return resource_id_map_.count(name) > 0;
}
v8::Handle<v8::String> ResourceBundleSourceMap::ConvertString(
diff --git a/chrome/renderer/resources/extensions/app.js b/chrome/renderer/resources/extensions/app.js
new file mode 100644
index 0000000..7337d86
--- /dev/null
+++ b/chrome/renderer/resources/extensions/app.js
@@ -0,0 +1,41 @@
+// 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
deleted file mode 100644
index 0164f9e..0000000
--- a/chrome/renderer/resources/extensions/app_custom_bindings.js
+++ /dev/null
@@ -1,56 +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.
-
-// Custom bindings for the app API.
-
-var appNatives = requireNative('app');
-var chromeHidden = requireNative('chrome_hidden').GetChromeHidden();
-
-chromeHidden.registerCustomHook('app', function(bindingsAPI) {
- var apiFunctions = bindingsAPI.apiFunctions;
-
- // Note: everything in chrome.app is synchronous.
- apiFunctions.setHandleRequest('getIsInstalled', appNatives.GetIsInstalled);
- apiFunctions.setHandleRequest('install', appNatives.Install);
- apiFunctions.setHandleRequest('getDetails', appNatives.GetDetails);
- apiFunctions.setHandleRequest('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 = new function() {
- this.getChannel = function(clientId, callback) {
- var callbackId = 0;
- if (callback) {
- callbackId = nextCallbackId++;
- callbacks[callbackId] = callback;
- }
- appNatives.GetAppNotifyChannel(clientId, callbackId);
- };
- }();
-});
diff --git a/chrome/renderer/resources/extensions/setup_bindings.js b/chrome/renderer/resources/extensions/setup_bindings.js
index 48a3ac7..86b0cd5 100644
--- a/chrome/renderer/resources/extensions/setup_bindings.js
+++ b/chrome/renderer/resources/extensions/setup_bindings.js
@@ -2,16 +2,20 @@
// 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('app');
require('webstore');
-require('json_schema');
-require('event_bindings');
-require('miscellaneous_bindings');
-require('schema_generated_bindings');
-require('apitest');
-// Load the custom bindings for each API.
-sgb.GetExtensionAPIDefinition().forEach(function(apiDef) {
- require(apiDef.namespace);
-});
+if (contextInfo.IsBindingsAllowed()) {
+ 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 572f280..3e37a3a 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,15 +28,11 @@ if (chrome.storage) {
success = false;
}
-// 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;
-}
-
-// Parts of chrome.extension are unavailable.
+// 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; }))
success = false;
+if (!runsWithException(function() { return chrome.tabs.create; }))
+ 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 3eacb11..79e491c 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) 2012 The Chromium Authors. All rights reserved.
+// Copyright (c) 2011 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 (module.unprivileged || entry.unprivileged) {
+ if (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.unprivileged || module.properties[propName].unprivileged) {
+ if (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 undefined or
+ // This is the last component - we expect it to either be defined or
// to throw an error on access.
try {
if (typeof(module[parts[i]]) == "undefined" &&