diff options
author | kalman@chromium.org <kalman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-21 04:09:23 +0000 |
---|---|---|
committer | kalman@chromium.org <kalman@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-03-21 04:09:23 +0000 |
commit | 46babb29a2e0f45d940a3197c74ddfa3b7abb7bf (patch) | |
tree | 59aa719c22084d760027e0b38d9d4d668342dda6 /chrome/renderer | |
parent | cd2c46e818a21cef01ccdf7c13bf3577d228e894 (diff) | |
download | chromium_src-46babb29a2e0f45d940a3197c74ddfa3b7abb7bf.zip chromium_src-46babb29a2e0f45d940a3197c74ddfa3b7abb7bf.tar.gz chromium_src-46babb29a2e0f45d940a3197c74ddfa3b7abb7bf.tar.bz2 |
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
Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=125811
Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=127391
Review URL: http://codereview.chromium.org/9460002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@127899 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer')
16 files changed, 220 insertions, 376 deletions
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); -}); |