summaryrefslogtreecommitdiffstats
path: root/chrome/renderer
diff options
context:
space:
mode:
authormpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-23 21:31:06 +0000
committermpcomplete@chromium.org <mpcomplete@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-09-23 21:31:06 +0000
commitaf7eb3fb5d0666d37b5c754c2976cc1276b66323 (patch)
tree4623bf0e86a9e20a5c94090b43094da34b26871c /chrome/renderer
parent943ca53d131a04f71e18fd140780b39304492ec1 (diff)
downloadchromium_src-af7eb3fb5d0666d37b5c754c2976cc1276b66323.zip
chromium_src-af7eb3fb5d0666d37b5c754c2976cc1276b66323.tar.gz
chromium_src-af7eb3fb5d0666d37b5c754c2976cc1276b66323.tar.bz2
Trying to reland r59889, this time as a multi-stage patch.
Fix regression introduced by http://src.chromium.org/viewvc/chrome?view=rev&revision=57788 Add a delegate interface so that chromium have more fine-grained control over whether a V8 extension is injected into a script context. This is the chromium-side change of webkit bug https://bugs.webkit.org/show_bug.cgi?id=45721 BUG=37290 TEST=covered by unit tests Review URL: http://codereview.chromium.org/3464005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@60350 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer')
-rw-r--r--chrome/renderer/extensions/event_bindings.cc24
-rw-r--r--chrome/renderer/render_thread.cc110
-rw-r--r--chrome/renderer/render_thread.h21
-rw-r--r--chrome/renderer/render_view.cc17
-rw-r--r--chrome/renderer/render_view.h3
5 files changed, 100 insertions, 75 deletions
diff --git a/chrome/renderer/extensions/event_bindings.cc b/chrome/renderer/extensions/event_bindings.cc
index 54edbb4..6f3b7e3 100644
--- a/chrome/renderer/extensions/event_bindings.cc
+++ b/chrome/renderer/extensions/event_bindings.cc
@@ -262,18 +262,11 @@ void EventBindings::HandleContextCreated(WebFrame* frame, bool content_script) {
GURL url = ds->request().url();
std::string extension_id = ExtensionRendererInfo::GetIdByURL(url);
- // Note: because process isolation doesn't work correcly with redirects,
- // it is possible that a page that IS in an extension process won't have
- // bindings setup for it, so we must also check IsExtensionProcess, otherwise
- // we'll attempt to invoke a JS function that doesn't exist.
- // Fixing crbug.com/53610 should fix this as well.
- RenderThread* current_thread = RenderThread::current();
- if ((!current_thread ||
- !current_thread->IsExtensionProcess() ||
- !ExtensionRendererInfo::ExtensionBindingsAllowed(url)) &&
+ if (!ExtensionRendererInfo::ExtensionBindingsAllowed(url) &&
!content_script) {
- // This context is a regular non-extension web page. Ignore it. We only
- // care about content scripts and extension frames.
+ // This context is a regular non-extension web page or an unprivileged
+ // chrome app. Ignore it. We only care about content scripts and extension
+ // frames.
// (Unless we're in unit tests, in which case we don't care what the URL
// is).
DCHECK(frame_context.IsEmpty() || frame_context == context);
@@ -305,9 +298,12 @@ void EventBindings::HandleContextCreated(WebFrame* frame, bool content_script) {
new ContextInfo(persistent_context, extension_id, parent_frame,
render_view)));
- v8::Handle<v8::Value> argv[1];
- argv[0] = v8::String::New(extension_id.c_str());
- CallFunctionInContext(context, "dispatchOnLoad", arraysize(argv), argv);
+ // Content scripts get initialized in user_script_slave.cc.
+ if (!content_script) {
+ v8::Handle<v8::Value> argv[1];
+ argv[0] = v8::String::New(extension_id.c_str());
+ CallFunctionInContext(context, "dispatchOnLoad", arraysize(argv), argv);
+ }
}
// static
diff --git a/chrome/renderer/render_thread.cc b/chrome/renderer/render_thread.cc
index 2729d14..6fdecc5 100644
--- a/chrome/renderer/render_thread.cc
+++ b/chrome/renderer/render_thread.cc
@@ -849,80 +849,40 @@ void RenderThread::EnsureWebKitInitialized() {
#if defined(OS_WIN)
// We don't yet support Gears on non-Windows, so don't tell pages that we do.
- WebScriptController::registerExtension(extensions_v8::GearsExtension::Get());
+ RegisterExtension(extensions_v8::GearsExtension::Get(), false);
#endif
- WebScriptController::registerExtension(
- extensions_v8::LoadTimesExtension::Get());
- WebScriptController::registerExtension(
- extensions_v8::ChromeAppExtension::Get());
- WebScriptController::registerExtension(
- extensions_v8::ExternalExtension::Get());
+ RegisterExtension(extensions_v8::LoadTimesExtension::Get(), false);
+ RegisterExtension(extensions_v8::ChromeAppExtension::Get(), false);
+ RegisterExtension(extensions_v8::ExternalExtension::Get(), false);
v8::Extension* search_extension = extensions_v8::SearchExtension::Get();
// search_extension is null if not enabled.
if (search_extension)
- WebScriptController::registerExtension(search_extension);
-
- // TODO(rafaelw). Note that extension-related v8 extensions are being
- // bound currently based on is_extension_process_. This means that
- // non-extension renderers that slip into an extension process (for example,
- // an extension page opening an iframe) will be extension bindings setup.
- // This should be relatively rare, and the offending page won't be able to
- // make extension API requests because it'll be denied on both sides of
- // the renderer by a permission check. However, this is still fairly lame
- // and we should consider implementing a V8Proxy delegate that calls out
- // to the render thread and makes a decision as to whether to bind these
- // extensions based on the frame's url.
- // See: crbug.com/53610.
-
- if (is_extension_process_)
- WebScriptController::registerExtension(ExtensionProcessBindings::Get());
-
- WebScriptController::registerExtension(
- BaseJsV8Extension::Get(), EXTENSION_GROUP_CONTENT_SCRIPTS);
- if (is_extension_process_)
- WebScriptController::registerExtension(BaseJsV8Extension::Get());
-
- WebScriptController::registerExtension(
- JsonSchemaJsV8Extension::Get(), EXTENSION_GROUP_CONTENT_SCRIPTS);
- if (is_extension_process_)
- WebScriptController::registerExtension(JsonSchemaJsV8Extension::Get());
-
- WebScriptController::registerExtension(
- EventBindings::Get(), EXTENSION_GROUP_CONTENT_SCRIPTS);
- if (is_extension_process_)
- WebScriptController::registerExtension(EventBindings::Get());
-
- WebScriptController::registerExtension(
- RendererExtensionBindings::Get(), EXTENSION_GROUP_CONTENT_SCRIPTS);
- if (is_extension_process_)
- WebScriptController::registerExtension(RendererExtensionBindings::Get());
-
- WebScriptController::registerExtension(
- ExtensionApiTestV8Extension::Get(), EXTENSION_GROUP_CONTENT_SCRIPTS);
- if (is_extension_process_)
- WebScriptController::registerExtension(
- ExtensionApiTestV8Extension::Get());
-
- web_database_observer_impl_.reset(new WebDatabaseObserverImpl(this));
- WebKit::WebDatabase::setObserver(web_database_observer_impl_.get());
+ RegisterExtension(search_extension, false);
const CommandLine& command_line = *CommandLine::ForCurrentProcess();
- if (command_line.HasSwitch(switches::kEnableBenchmarking)) {
- WebScriptController::registerExtension(
- extensions_v8::BenchmarkingExtension::Get());
- }
+ if (command_line.HasSwitch(switches::kEnableBenchmarking))
+ RegisterExtension(extensions_v8::BenchmarkingExtension::Get(), false);
if (command_line.HasSwitch(switches::kPlaybackMode) ||
command_line.HasSwitch(switches::kRecordMode) ||
command_line.HasSwitch(switches::kNoJsRandomness)) {
- WebScriptController::registerExtension(
- extensions_v8::PlaybackExtension::Get());
+ RegisterExtension(extensions_v8::PlaybackExtension::Get(), false);
}
- if (command_line.HasSwitch(switches::kDomAutomationController)) {
- WebScriptController::registerExtension(DomAutomationV8Extension::Get());
- }
+ if (command_line.HasSwitch(switches::kDomAutomationController))
+ RegisterExtension(DomAutomationV8Extension::Get(), false);
+
+ // Add v8 extensions related to chrome extensions.
+ RegisterExtension(ExtensionProcessBindings::Get(), true);
+ RegisterExtension(BaseJsV8Extension::Get(), true);
+ RegisterExtension(JsonSchemaJsV8Extension::Get(), true);
+ RegisterExtension(EventBindings::Get(), true);
+ RegisterExtension(RendererExtensionBindings::Get(), true);
+ RegisterExtension(ExtensionApiTestV8Extension::Get(), true);
+
+ web_database_observer_impl_.reset(new WebDatabaseObserverImpl(this));
+ WebKit::WebDatabase::setObserver(web_database_observer_impl_.get());
WebRuntimeFeatures::enableMediaPlayer(
RenderProcess::current()->HasInitializedMediaLibrary());
@@ -1119,3 +1079,31 @@ RenderThread::GetFileThreadMessageLoopProxy() {
}
return file_thread_->message_loop_proxy();
}
+
+bool RenderThread::AllowScriptExtension(const std::string& v8_extension_name,
+ const GURL& url,
+ int extension_group) {
+ // If we don't know about it, it was added by WebCore, so we should allow it.
+ if (v8_extensions_.find(v8_extension_name) == v8_extensions_.end())
+ return true;
+
+ // If the V8 extension is not restricted, allow it to run anywhere.
+ bool restrict_to_extensions = v8_extensions_[v8_extension_name];
+ if (!restrict_to_extensions)
+ return true;
+
+ // Extension-only bindings should be restricted to content scripts and
+ // extension-blessed URLs.
+ if (extension_group == EXTENSION_GROUP_CONTENT_SCRIPTS ||
+ ExtensionRendererInfo::ExtensionBindingsAllowed(url)) {
+ return true;
+ }
+
+ return false;
+}
+
+void RenderThread::RegisterExtension(v8::Extension* extension,
+ bool restrict_to_extensions) {
+ WebScriptController::registerExtension(extension);
+ v8_extensions_[extension->name()] = restrict_to_extensions;
+}
diff --git a/chrome/renderer/render_thread.h b/chrome/renderer/render_thread.h
index 6b28214..4572b49 100644
--- a/chrome/renderer/render_thread.h
+++ b/chrome/renderer/render_thread.h
@@ -6,6 +6,7 @@
#define CHROME_RENDERER_RENDER_THREAD_H_
#pragma once
+#include <map>
#include <string>
#include <vector>
@@ -60,6 +61,10 @@ namespace WebKit {
class WebStorageEventDispatcher;
}
+namespace v8 {
+class Extension;
+}
+
// The RenderThreadBase is the minimal interface that a RenderView/Widget
// expects from a render thread. The interface basically abstracts a way to send
// and receive messages.
@@ -231,6 +236,13 @@ class RenderThread : public RenderThreadBase,
// on the renderer's main thread.
scoped_refptr<base::MessageLoopProxy> GetFileThreadMessageLoopProxy();
+ // This function is called for every registered V8 extension each time a new
+ // script context is created. Returns true if the given V8 extension is
+ // allowed to run on the given URL and extension group.
+ bool AllowScriptExtension(const std::string& v8_extension_name,
+ const GURL& url,
+ int extension_group);
+
private:
virtual void OnControlMessageReceived(const IPC::Message& msg);
@@ -311,6 +323,10 @@ class RenderThread : public RenderThreadBase,
// Schedule a call to IdleHandler with the given initial delay.
void ScheduleIdleHandler(double initial_delay_s);
+ // Registers the given V8 extension with WebKit, and also tracks what pages
+ // it is allowed to run on.
+ void RegisterExtension(v8::Extension* extension, bool restrict_to_extensions);
+
// These objects live solely on the render thread.
scoped_ptr<ScopedRunnableMethodFactory<RenderThread> > task_factory_;
scoped_ptr<VisitedLinkSlave> visited_link_slave_;
@@ -371,6 +387,11 @@ class RenderThread : public RenderThreadBase,
// A lazily initiated thread on which file operations are run.
scoped_ptr<base::Thread> file_thread_;
+ // Map of registered v8 extensions. The key is the extension name. The value
+ // is true if the extension should be restricted to extension-related
+ // contexts.
+ std::map<std::string, bool> v8_extensions_;
+
DISALLOW_COPY_AND_ASSIGN(RenderThread);
};
diff --git a/chrome/renderer/render_view.cc b/chrome/renderer/render_view.cc
index ae155e8..8dceb39 100644
--- a/chrome/renderer/render_view.cc
+++ b/chrome/renderer/render_view.cc
@@ -3408,6 +3408,23 @@ void RenderView::didCreateIsolatedScriptContext(WebFrame* frame) {
EventBindings::HandleContextCreated(frame, true);
}
+bool RenderView::allowScriptExtension(WebFrame* frame,
+ const WebString& extension_name,
+ int extension_group) {
+ // NULL in unit tests.
+ if (!RenderThread::current())
+ return true;
+
+ // Note: we prefer the provisional URL here instead of the document URL
+ // because we might be currently loading an URL into a blank page.
+ // See http://code.google.com/p/chromium/issues/detail?id=10924
+ WebDataSource* ds = frame->provisionalDataSource();
+ if (!ds)
+ ds = frame->dataSource();
+ return RenderThread::current()->AllowScriptExtension(
+ extension_name.utf8(), ds->request().url(), extension_group);
+}
+
void RenderView::logCrossFramePropertyAccess(WebFrame* frame,
WebFrame* target,
bool cross_origin,
diff --git a/chrome/renderer/render_view.h b/chrome/renderer/render_view.h
index 01f9655..bf43b2e 100644
--- a/chrome/renderer/render_view.h
+++ b/chrome/renderer/render_view.h
@@ -553,6 +553,9 @@ class RenderView : public RenderWidget,
virtual void didCreateScriptContext(WebKit::WebFrame* frame);
virtual void didDestroyScriptContext(WebKit::WebFrame* frame);
virtual void didCreateIsolatedScriptContext(WebKit::WebFrame* frame);
+ virtual bool allowScriptExtension(WebKit::WebFrame*,
+ const WebKit::WebString& extension_name,
+ int extensionGroup);
virtual void logCrossFramePropertyAccess(
WebKit::WebFrame* frame,
WebKit::WebFrame* target,