summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/extensions/api/guest_view/guest_view_internal_api.cc8
-rw-r--r--chrome/browser/extensions/extension_webui_apitest.cc31
-rw-r--r--chrome/browser/guest_view/extension_options/extension_options_guest.cc4
-rw-r--r--chrome/browser/ui/webui/extensions/extensions_ui.cc4
-rw-r--r--chrome/common/extensions/api/_api_features.json14
-rw-r--r--chrome/renderer/chrome_content_renderer_client.cc29
-rw-r--r--chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc8
-rw-r--r--chrome/test/data/extensions/webui/can_embed_extension_options.js23
8 files changed, 99 insertions, 22 deletions
diff --git a/chrome/browser/extensions/api/guest_view/guest_view_internal_api.cc b/chrome/browser/extensions/api/guest_view/guest_view_internal_api.cc
index 0e898a4..caaadbb 100644
--- a/chrome/browser/extensions/api/guest_view/guest_view_internal_api.cc
+++ b/chrome/browser/extensions/api/guest_view/guest_view_internal_api.cc
@@ -40,9 +40,15 @@ bool GuestViewInternalCreateGuestFunction::RunAsync() {
error_ = "Guest views can only be embedded in web content";
return false;
}
+ // If the guest is an <extensionoptions> to be embedded in a WebUI, then
+ // there is no extension, and extension() will be null. Use an empty string
+ // instead.
+ std::string embedder_extension_id;
+ if (extension())
+ embedder_extension_id = extension_id();
guest_view_manager->CreateGuest(view_type,
- extension_id(),
+ embedder_extension_id,
embedder_web_contents,
*create_params,
callback);
diff --git a/chrome/browser/extensions/extension_webui_apitest.cc b/chrome/browser/extensions/extension_webui_apitest.cc
index dcd40d3..156c6c0 100644
--- a/chrome/browser/extensions/extension_webui_apitest.cc
+++ b/chrome/browser/extensions/extension_webui_apitest.cc
@@ -18,6 +18,8 @@
#include "extensions/browser/event_router.h"
#include "extensions/common/api/test.h"
#include "extensions/common/extension.h"
+#include "extensions/common/feature_switch.h"
+#include "extensions/common/switches.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace extensions {
@@ -108,6 +110,18 @@ class ExtensionWebUITest : public ExtensionApiTest {
base::Bind(&FindFrame, frame_url, &frame_host));
return frame_host;
}
+
+ virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE {
+ FeatureSwitch::ScopedOverride enable_options(
+ FeatureSwitch::embedded_extension_options(), true);
+ // Need to add a command line flag as well as a FeatureSwitch because the
+ // FeatureSwitch is not copied over to the renderer process from the
+ // browser process.
+ command_line->AppendSwitch(switches::kEnableEmbeddedExtensionOptions);
+ ExtensionApiTest::SetUpCommandLine(command_line);
+ }
+
+ scoped_ptr<FeatureSwitch::ScopedOverride> enable_options_;
};
IN_PROC_BROWSER_TEST_F(ExtensionWebUITest, SanityCheckAvailableAPIs) {
@@ -167,6 +181,23 @@ IN_PROC_BROWSER_TEST_F(ExtensionWebUITest, RuntimeLastError) {
EXPECT_EQ("true", listener->message());
}
+IN_PROC_BROWSER_TEST_F(ExtensionWebUITest, CanEmbedExtensionOptions) {
+ scoped_ptr<ExtensionTestMessageListener> listener(
+ new ExtensionTestMessageListener("ready", true));
+
+ const Extension* extension = InstallExtension(
+ test_data_dir_.AppendASCII("extension_options").AppendASCII("embed_self"),
+ 1);
+ ASSERT_TRUE(extension);
+
+ ASSERT_TRUE(RunTestOnExtensions("can_embed_extension_options.js"));
+
+ ASSERT_TRUE(listener->WaitUntilSatisfied());
+ listener->Reply(extension->id());
+ listener.reset(new ExtensionTestMessageListener("guest loaded", false));
+ ASSERT_TRUE(listener->WaitUntilSatisfied());
+}
+
} // namespace
} // namespace extensions
diff --git a/chrome/browser/guest_view/extension_options/extension_options_guest.cc b/chrome/browser/guest_view/extension_options/extension_options_guest.cc
index 6d89f6f..f7ca290 100644
--- a/chrome/browser/guest_view/extension_options/extension_options_guest.cc
+++ b/chrome/browser/guest_view/extension_options/extension_options_guest.cc
@@ -64,7 +64,9 @@ void ExtensionOptionsGuest::CreateWebContents(
return;
}
- if (extension_id != embedder_extension_id) {
+ if (extensions::Extension::IdIsValid(embedder_extension_id) &&
+ extension_id != embedder_extension_id) {
+ // Extensions cannot embed other extensions' options pages.
callback.Run(NULL);
return;
}
diff --git a/chrome/browser/ui/webui/extensions/extensions_ui.cc b/chrome/browser/ui/webui/extensions/extensions_ui.cc
index 34902aa..fab449d 100644
--- a/chrome/browser/ui/webui/extensions/extensions_ui.cc
+++ b/chrome/browser/ui/webui/extensions/extensions_ui.cc
@@ -84,6 +84,10 @@ ExtensionsUI::ExtensionsUI(content::WebUI* web_ui) : WebUIController(web_ui) {
web_ui->AddMessageHandler(new MetricsHandler());
+ // Need to allow <object> elements so that the <extensionoptions> browser
+ // plugin can be loaded within chrome://extensions.
+ source->OverrideContentSecurityPolicyObjectSrc("object-src 'self';");
+
content::WebUIDataSource::Add(profile, source);
}
diff --git a/chrome/common/extensions/api/_api_features.json b/chrome/common/extensions/api/_api_features.json
index 7051eb5..d0ebe4f 100644
--- a/chrome/common/extensions/api/_api_features.json
+++ b/chrome/common/extensions/api/_api_features.json
@@ -375,11 +375,16 @@
"extension.sendRequest": {
"contexts": ["blessed_extension", "unblessed_extension", "content_script"]
},
- "extensionOptionsInternal": {
+ "extensionOptionsInternal": [{
"internal": true,
"contexts": ["blessed_extension"],
"dependencies": ["permission:embeddedExtensionOptions"]
- },
+ }, {
+ "internal": true,
+ "channel": "trunk",
+ "contexts": ["webui"],
+ "matches": ["chrome://extensions-frame/*", "chrome://extensions/*"]
+ }],
// This is not a real API, only here for documentation purposes.
// See http://crbug.com/275944 for background.
"extensionsManifestTypes": {
@@ -453,6 +458,11 @@
"internal": true,
"dependencies": ["permission:webview"],
"contexts": ["unblessed_extension"]
+ }, {
+ "internal": true,
+ "channel": "trunk",
+ "contexts": ["webui"],
+ "matches": ["chrome://extensions-frame/*", "chrome://extensions/*"]
}],
"hangoutsPrivate": {
"channel": "stable",
diff --git a/chrome/renderer/chrome_content_renderer_client.cc b/chrome/renderer/chrome_content_renderer_client.cc
index a5094ce..9eb68b5 100644
--- a/chrome/renderer/chrome_content_renderer_client.cc
+++ b/chrome/renderer/chrome_content_renderer_client.cc
@@ -245,6 +245,14 @@ bool ShouldUseJavaScriptSettingForPlugin(const WebPluginInfo& plugin) {
return false;
}
+void IsGuestViewApiAvailableToScriptContext(
+ bool* api_is_available,
+ extensions::ScriptContext* context) {
+ if (context->GetAvailability("guestViewInternal").is_available()) {
+ *api_is_available = true;
+ }
+}
+
} // namespace
ChromeContentRendererClient::ChromeContentRendererClient() {
@@ -520,20 +528,13 @@ bool ChromeContentRendererClient::OverrideCreatePlugin(
WebPlugin** plugin) {
std::string orig_mime_type = params.mimeType.utf8();
if (orig_mime_type == content::kBrowserPluginMimeType) {
- WebDocument document = frame->document();
- const Extension* extension =
- GetExtensionByOrigin(document.securityOrigin());
- if (extension) {
- const extensions::APIPermission::ID perms[] = {
- extensions::APIPermission::kAppView,
- extensions::APIPermission::kEmbeddedExtensionOptions,
- extensions::APIPermission::kWebView,
- };
- for (size_t i = 0; i < arraysize(perms); ++i) {
- if (extension->permissions_data()->HasAPIPermission(perms[i]))
- return false;
- }
- }
+ bool guest_view_api_available = false;
+ extension_dispatcher_->script_context_set().ForEach(
+ render_frame->GetRenderView(),
+ base::Bind(&IsGuestViewApiAvailableToScriptContext,
+ &guest_view_api_available));
+ if (guest_view_api_available)
+ return false;
}
ChromeViewHostMsg_GetPluginInfo_Output output;
diff --git a/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc b/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc
index 960b675..47600fb 100644
--- a/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc
+++ b/chrome/renderer/extensions/chrome_extensions_dispatcher_delegate.cc
@@ -289,6 +289,7 @@ void ChromeExtensionsDispatcherDelegate::RequireAdditionalModules(
// The API will be automatically set up when first used.
if (context_type == extensions::Feature::BLESSED_EXTENSION_CONTEXT ||
context_type == extensions::Feature::UNBLESSED_EXTENSION_CONTEXT) {
+ // TODO(fsamuel): Use context->GetAvailability("webViewInternal").
if (extension->permissions_data()->HasAPIPermission(
extensions::APIPermission::kWebView)) {
module_system->Require("webView");
@@ -313,6 +314,7 @@ void ChromeExtensionsDispatcherDelegate::RequireAdditionalModules(
}
if (context_type == extensions::Feature::BLESSED_EXTENSION_CONTEXT) {
+ // TODO(fsamuel): Use context->GetAvailability("appViewInternal").
if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kEnableAppView) &&
extension->permissions_data()->HasAPIPermission(
extensions::APIPermission::kAppView)) {
@@ -322,10 +324,8 @@ void ChromeExtensionsDispatcherDelegate::RequireAdditionalModules(
}
}
- if (context_type == extensions::Feature::BLESSED_EXTENSION_CONTEXT &&
- extensions::FeatureSwitch::embedded_extension_options()->IsEnabled() &&
- extension->permissions_data()->HasAPIPermission(
- extensions::APIPermission::kEmbeddedExtensionOptions)) {
+ if (extensions::FeatureSwitch::embedded_extension_options()->IsEnabled() &&
+ context->GetAvailability("extensionOptionsInternal").is_available()) {
module_system->Require("extensionOptions");
}
}
diff --git a/chrome/test/data/extensions/webui/can_embed_extension_options.js b/chrome/test/data/extensions/webui/can_embed_extension_options.js
new file mode 100644
index 0000000..57f538d
--- /dev/null
+++ b/chrome/test/data/extensions/webui/can_embed_extension_options.js
@@ -0,0 +1,23 @@
+// Copyright 2014 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.
+
+// out/Debug/browser_tests
+// --gtest_filter=ExtensionWebUITest.CanEmbedExtensionOptions
+if (!chrome || !chrome.test || !chrome.test.sendMessage) {
+ console.error('chrome.test.sendMessage is unavailable on ' +
+ document.location.href);
+ domAutomationController.send(false);
+ return;
+}
+
+chrome.test.sendMessage('ready', function(reply) {
+ var extensionoptions = document.createElement('extensionoptions');
+ extensionoptions.addEventListener('load', function() {
+ chrome.test.sendMessage('guest loaded');
+ });
+ extensionoptions.setAttribute('extension', reply);
+ document.body.appendChild(extensionoptions);
+});
+
+domAutomationController.send(true);