summaryrefslogtreecommitdiffstats
path: root/chrome/renderer/extensions
diff options
context:
space:
mode:
authoraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-06 04:24:05 +0000
committeraa@chromium.org <aa@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-09-06 04:24:05 +0000
commit1eb5a2298dbc3dc3d30272847cdaa3e6b4d2791d (patch)
treed1e3f3daac83f66b73dc06daf5c1c8e58a88d3b0 /chrome/renderer/extensions
parent46018c9d614cd47961cad5a39416687ebdd8d1cd (diff)
downloadchromium_src-1eb5a2298dbc3dc3d30272847cdaa3e6b4d2791d.zip
chromium_src-1eb5a2298dbc3dc3d30272847cdaa3e6b4d2791d.tar.gz
chromium_src-1eb5a2298dbc3dc3d30272847cdaa3e6b4d2791d.tar.bz2
Revert 99689 - Refactor the ContextInfo struct from bindings_utils into a
real class. Pull functionality from bindings_utils and event_bindings in as methods. Simplify lifetime management. Review URL: http://codereview.chromium.org/7792090 TBR=aa@chromium.org Review URL: http://codereview.chromium.org/7800034 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@99694 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/renderer/extensions')
-rw-r--r--chrome/renderer/extensions/bindings_utils.cc131
-rw-r--r--chrome/renderer/extensions/bindings_utils.h89
-rw-r--r--chrome/renderer/extensions/chrome_app_bindings.cc1
-rw-r--r--chrome/renderer/extensions/chrome_webstore_bindings.cc1
-rw-r--r--chrome/renderer/extensions/event_bindings.cc270
-rw-r--r--chrome/renderer/extensions/event_bindings.h38
-rw-r--r--chrome/renderer/extensions/extension_api_json_validity_unittest.cc1
-rw-r--r--chrome/renderer/extensions/extension_base.cc31
-rw-r--r--chrome/renderer/extensions/extension_base.h8
-rw-r--r--chrome/renderer/extensions/extension_bindings_context.cc235
-rw-r--r--chrome/renderer/extensions/extension_bindings_context.h95
-rw-r--r--chrome/renderer/extensions/extension_dispatcher.cc3
-rw-r--r--chrome/renderer/extensions/extension_helper.cc3
-rw-r--r--chrome/renderer/extensions/extension_process_bindings.cc39
-rw-r--r--chrome/renderer/extensions/renderer_extension_bindings.cc1
15 files changed, 537 insertions, 409 deletions
diff --git a/chrome/renderer/extensions/bindings_utils.cc b/chrome/renderer/extensions/bindings_utils.cc
new file mode 100644
index 0000000..3cad5ea
--- /dev/null
+++ b/chrome/renderer/extensions/bindings_utils.cc
@@ -0,0 +1,131 @@
+// 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.
+
+#include "chrome/renderer/extensions/bindings_utils.h"
+
+#include "base/lazy_instance.h"
+#include "base/string_split.h"
+#include "base/string_util.h"
+#include "content/renderer/render_view.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
+#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
+#include "v8/include/v8.h"
+
+using WebKit::WebFrame;
+using WebKit::WebView;
+
+namespace bindings_utils {
+
+const char* kChromeHidden = "chromeHidden";
+const char* kValidateCallbacks = "validateCallbacks";
+
+struct SingletonData {
+ ContextList contexts;
+ PendingRequestMap pending_requests;
+};
+static base::LazyInstance<SingletonData> g_singleton_data(
+ base::LINKER_INITIALIZED);
+
+ContextInfo::ContextInfo(v8::Persistent<v8::Context> context,
+ const std::string& extension_id,
+ WebFrame* frame)
+ : context(context),
+ extension_id(extension_id),
+ unsafe_frame(frame),
+ num_connected_events(0) {
+}
+
+ContextInfo::~ContextInfo() {}
+
+ContextList& GetContexts() {
+ return g_singleton_data.Get().contexts;
+}
+
+ContextInfo* GetInfoForCurrentContext() {
+ // This can happen in testing scenarios and v8::Context::GetCurrent() crashes
+ // if there is no JavaScript currently running.
+ if (!v8::Context::InContext())
+ return NULL;
+
+ v8::Local<v8::Context> context = v8::Context::GetCurrent();
+ ContextList::iterator context_iter = FindContext(context);
+ if (context_iter == GetContexts().end())
+ return NULL;
+ else
+ return context_iter->get();
+}
+
+v8::Handle<v8::Object> GetChromeHiddenForContext(
+ v8::Handle<v8::Context> context) {
+ v8::Local<v8::Object> global = context->Global();
+ v8::Local<v8::Value> hidden = global->GetHiddenValue(
+ v8::String::New(kChromeHidden));
+
+ if (hidden.IsEmpty() || hidden->IsUndefined()) {
+ hidden = v8::Object::New();
+ global->SetHiddenValue(v8::String::New(kChromeHidden), hidden);
+
+#ifndef NDEBUG
+ // Tell extension_process_bindings.js to validate callbacks and events
+ // against their schema definitions in api/extension_api.json.
+ v8::Local<v8::Object>::Cast(hidden)
+ ->Set(v8::String::New(kValidateCallbacks), v8::True());
+#endif
+ }
+
+ DCHECK(hidden->IsObject());
+ return v8::Local<v8::Object>::Cast(hidden);
+}
+
+PendingRequest::PendingRequest(v8::Persistent<v8::Context> context,
+ const std::string& name)
+ : context(context), name(name) {
+}
+
+PendingRequest::~PendingRequest() {}
+
+ContextList::iterator FindContext(v8::Handle<v8::Context> context) {
+ ContextList& all_contexts = GetContexts();
+
+ ContextList::iterator it = all_contexts.begin();
+ for (; it != all_contexts.end(); ++it) {
+ if ((*it)->context == context)
+ break;
+ }
+
+ return it;
+}
+
+PendingRequestMap& GetPendingRequestMap() {
+ return g_singleton_data.Get().pending_requests;
+}
+
+v8::Handle<v8::Value> CallFunctionInContext(v8::Handle<v8::Context> context,
+ const std::string& function_name, int argc,
+ v8::Handle<v8::Value>* argv) {
+ v8::Context::Scope context_scope(context);
+
+ // Look up the function name, which may be a sub-property like
+ // "Port.dispatchOnMessage" in the hidden global variable.
+ v8::Local<v8::Value> value =
+ context->Global()->GetHiddenValue(v8::String::New(kChromeHidden));
+ std::vector<std::string> components;
+ base::SplitStringDontTrim(function_name, '.', &components);
+ for (size_t i = 0; i < components.size(); ++i) {
+ if (!value.IsEmpty() && value->IsObject())
+ value = value->ToObject()->Get(v8::String::New(components[i].c_str()));
+ }
+ if (value.IsEmpty() || !value->IsFunction()) {
+ NOTREACHED();
+ return v8::Undefined();
+ }
+
+ v8::Local<v8::Function> function = v8::Local<v8::Function>::Cast(value);
+ if (!function.IsEmpty())
+ return function->Call(v8::Object::New(), argc, argv);
+
+ return v8::Undefined();
+}
+
+} // namespace bindings_utils
diff --git a/chrome/renderer/extensions/bindings_utils.h b/chrome/renderer/extensions/bindings_utils.h
new file mode 100644
index 0000000..5318da9
--- /dev/null
+++ b/chrome/renderer/extensions/bindings_utils.h
@@ -0,0 +1,89 @@
+// 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.
+
+#ifndef CHROME_RENDERER_EXTENSIONS_BINDINGS_UTILS_H_
+#define CHROME_RENDERER_EXTENSIONS_BINDINGS_UTILS_H_
+#pragma once
+
+#include "base/memory/linked_ptr.h"
+#include "base/memory/singleton.h"
+#include "v8/include/v8.h"
+
+#include <list>
+#include <map>
+#include <string>
+
+class RenderView;
+
+namespace WebKit {
+class WebFrame;
+}
+
+namespace bindings_utils {
+
+// Contains information about a JavaScript context that is hosting extension
+// bindings.
+struct ContextInfo {
+ ContextInfo(v8::Persistent<v8::Context> context,
+ const std::string& extension_id,
+ WebKit::WebFrame* frame);
+ ~ContextInfo();
+
+ v8::Persistent<v8::Context> context;
+
+ // The extension ID this context is associated with.
+ std::string extension_id;
+
+ // The frame the context is associated with. ContextInfo can outlive its
+ // frame, so this should not be dereferenced. It is stored only for use for
+ // comparison.
+ void* unsafe_frame;
+
+ // A count of the number of events that are listening in this context. When
+ // this is zero, |context| will be a weak handle.
+ int num_connected_events;
+};
+typedef std::list< linked_ptr<ContextInfo> > ContextList;
+
+// Returns a mutable reference to the ContextList. Note: be careful using this.
+// Calling into javascript may result in the list being modified, so don't rely
+// on iterators remaining valid between calls to javascript.
+ContextList& GetContexts();
+
+// Returns the ContextInfo item that has the given context.
+ContextList::iterator FindContext(v8::Handle<v8::Context> context);
+
+// Returns the ContextInfo for the current v8 context.
+ContextInfo* GetInfoForCurrentContext();
+
+// Returns the 'chromeHidden' object for the specified context.
+v8::Handle<v8::Object> GetChromeHiddenForContext(
+ v8::Handle<v8::Context> context);
+
+// Contains info relevant to a pending API request.
+struct PendingRequest {
+ public :
+ PendingRequest(v8::Persistent<v8::Context> context, const std::string& name);
+ ~PendingRequest();
+
+ v8::Persistent<v8::Context> context;
+ std::string name;
+};
+typedef std::map<int, linked_ptr<PendingRequest> > PendingRequestMap;
+
+// Returns a mutable reference to the PendingRequestMap.
+PendingRequestMap& GetPendingRequestMap();
+
+// Call the named javascript function with the given arguments in a context.
+// The function name should be reachable from the chromeHidden object, and can
+// be a sub-property like "Port.dispatchOnMessage". Returns the result of
+// the function call. If an exception is thrown an empty Handle will be
+// returned.
+v8::Handle<v8::Value> CallFunctionInContext(v8::Handle<v8::Context> context,
+ const std::string& function_name, int argc,
+ v8::Handle<v8::Value>* argv);
+
+} // namespace bindings_utils
+
+#endif // CHROME_RENDERER_EXTENSIONS_BINDINGS_UTILS_H_
diff --git a/chrome/renderer/extensions/chrome_app_bindings.cc b/chrome/renderer/extensions/chrome_app_bindings.cc
index b52b7ca..3f1ceba 100644
--- a/chrome/renderer/extensions/chrome_app_bindings.cc
+++ b/chrome/renderer/extensions/chrome_app_bindings.cc
@@ -12,6 +12,7 @@
#include "base/values.h"
#include "chrome/common/chrome_switches.h"
#include "chrome/common/extensions/extension_set.h"
+#include "chrome/renderer/extensions/bindings_utils.h"
#include "chrome/renderer/extensions/extension_dispatcher.h"
#include "chrome/renderer/extensions/extension_helper.h"
#include "content/renderer/render_view.h"
diff --git a/chrome/renderer/extensions/chrome_webstore_bindings.cc b/chrome/renderer/extensions/chrome_webstore_bindings.cc
index 1f32fa2..aa87e44 100644
--- a/chrome/renderer/extensions/chrome_webstore_bindings.cc
+++ b/chrome/renderer/extensions/chrome_webstore_bindings.cc
@@ -6,6 +6,7 @@
#include "base/string_util.h"
#include "chrome/common/extensions/extension.h"
+#include "chrome/renderer/extensions/bindings_utils.h"
#include "chrome/renderer/extensions/extension_helper.h"
#include "content/renderer/render_view.h"
#include "googleurl/src/gurl.h"
diff --git a/chrome/renderer/extensions/event_bindings.cc b/chrome/renderer/extensions/event_bindings.cc
index ed65e3f..9be737b 100644
--- a/chrome/renderer/extensions/event_bindings.cc
+++ b/chrome/renderer/extensions/event_bindings.cc
@@ -12,9 +12,10 @@
#include "chrome/common/extensions/extension_messages.h"
#include "chrome/common/extensions/extension_set.h"
#include "chrome/common/url_constants.h"
+#include "chrome/renderer/chrome_render_process_observer.h"
+#include "chrome/renderer/extensions/bindings_utils.h"
#include "chrome/renderer/extensions/event_bindings.h"
#include "chrome/renderer/extensions/extension_base.h"
-#include "chrome/renderer/extensions/extension_bindings_context.h"
#include "chrome/renderer/extensions/extension_dispatcher.h"
#include "chrome/renderer/extensions/extension_process_bindings.h"
#include "chrome/renderer/extensions/js_only_v8_extensions.h"
@@ -24,6 +25,7 @@
#include "content/renderer/v8_value_converter.h"
#include "googleurl/src/gurl.h"
#include "grit/renderer_resources.h"
+#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/WebSecurityOrigin.h"
@@ -32,14 +34,32 @@
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
#include "v8/include/v8.h"
+using bindings_utils::CallFunctionInContext;
+using bindings_utils::ContextInfo;
+using bindings_utils::ContextList;
+using bindings_utils::GetContexts;
+using bindings_utils::GetInfoForCurrentContext;
+using bindings_utils::GetPendingRequestMap;
+using bindings_utils::PendingRequestMap;
+using WebKit::WebDataSource;
+using WebKit::WebDocument;
using WebKit::WebFrame;
using WebKit::WebSecurityOrigin;
using WebKit::WebURL;
+static void ContextWeakReferenceCallback(v8::Persistent<v8::Value> context,
+ void*);
+
namespace {
// Keep a local cache of RenderThread so that we can mock it out for unit tests.
static RenderThreadBase* render_thread = NULL;
+static bool in_unit_tests = false;
+
+// Set to true if these bindings are registered. Will be false when extensions
+// are disabled.
+static bool bindings_registered = false;
+
// A map of event names to the number of listeners for that event. We notify
// the browser about event listeners when we transition between 0 and 1.
@@ -85,11 +105,9 @@ class ExtensionImpl : public ExtensionBase {
DCHECK(args[0]->IsString() || args[0]->IsUndefined());
if (args[0]->IsString()) {
- ExtensionBindingsContext* context =
- ExtensionBindingsContext::GetCurrent();
- CHECK(context);
+ ContextInfo* context_info = GetInfoForCurrentContext();
EventListenerCounts& listener_counts =
- GetListenerCounts(context->extension_id());
+ GetListenerCounts(context_info->extension_id);
std::string event_name(*v8::String::AsciiValue(args[0]));
ExtensionImpl* v8_extension = GetFromArguments<ExtensionImpl>(args);
@@ -98,9 +116,13 @@ class ExtensionImpl : public ExtensionBase {
if (++listener_counts[event_name] == 1) {
EventBindings::GetRenderThread()->Send(
- new ExtensionHostMsg_AddListener(context->extension_id(),
+ new ExtensionHostMsg_AddListener(context_info->extension_id,
event_name));
}
+
+ if (++context_info->num_connected_events == 1)
+ context_info->context.ClearWeak();
+
}
return v8::Undefined();
@@ -112,19 +134,22 @@ class ExtensionImpl : public ExtensionBase {
DCHECK(args[0]->IsString() || args[0]->IsUndefined());
if (args[0]->IsString()) {
- ExtensionBindingsContext* context =
- ExtensionBindingsContext::GetCurrent();
- if (!context)
+ ContextInfo* context_info = GetInfoForCurrentContext();
+ if (!context_info)
return v8::Undefined();
EventListenerCounts& listener_counts =
- GetListenerCounts(context->extension_id());
+ GetListenerCounts(context_info->extension_id);
std::string event_name(*v8::String::AsciiValue(args[0]));
if (--listener_counts[event_name] == 0) {
EventBindings::GetRenderThread()->Send(
- new ExtensionHostMsg_RemoveListener(context->extension_id(),
+ new ExtensionHostMsg_RemoveListener(context_info->extension_id,
event_name));
}
+
+ if (--context_info->num_connected_events == 0) {
+ context_info->context.MakeWeak(NULL, &ContextWeakReferenceCallback);
+ }
}
return v8::Undefined();
@@ -163,21 +188,244 @@ class ExtensionImpl : public ExtensionBase {
}
};
+// Returns true if the extension running in the given |context| has sufficient
+// permissions to access the data.
+static bool HasSufficientPermissions(RenderView* render_view,
+ const GURL& event_url) {
+ // During unit tests, we might be invoked without a v8 context. In these
+ // cases, we only allow empty event_urls and short-circuit before retrieving
+ // the render view from the current context.
+ if (!event_url.is_valid())
+ return true;
+
+ WebDocument document = render_view->webview()->mainFrame()->document();
+ return GURL(document.url()).SchemeIs(chrome::kExtensionScheme) &&
+ document.securityOrigin().canRequest(event_url);
+}
+
} // namespace
const char* EventBindings::kName = "chrome/EventBindings";
+const char* EventBindings::kTestingExtensionId =
+ "oooooooooooooooooooooooooooooooo";
v8::Extension* EventBindings::Get(ExtensionDispatcher* dispatcher) {
static v8::Extension* extension = new ExtensionImpl(dispatcher);
+ bindings_registered = true;
return extension;
}
// static
void EventBindings::SetRenderThread(RenderThreadBase* thread) {
render_thread = thread;
+ in_unit_tests = true;
}
// static
RenderThreadBase* EventBindings::GetRenderThread() {
return render_thread ? render_thread : RenderThread::current();
}
+
+static void DeferredUnload(v8::Persistent<v8::Context> context) {
+ v8::HandleScope handle_scope;
+ CallFunctionInContext(context, "dispatchOnUnload", 0, NULL);
+ context.Dispose();
+ context.Clear();
+}
+
+static void UnregisterContext(ContextList::iterator context_iter, bool in_gc) {
+ // Notify the bindings that they're going away.
+ if (in_gc) {
+ // We shouldn't call back into javascript during a garbage collect. Do it
+ // later. We'll hang onto the context until this DeferredUnload is called.
+ MessageLoop::current()->PostTask(FROM_HERE, NewRunnableFunction(
+ DeferredUnload, (*context_iter)->context));
+ } else {
+ CallFunctionInContext((*context_iter)->context, "dispatchOnUnload",
+ 0, NULL);
+ }
+
+ // Remove all pending requests for this context.
+ PendingRequestMap& pending_requests = GetPendingRequestMap();
+ for (PendingRequestMap::iterator it = pending_requests.begin();
+ it != pending_requests.end(); ) {
+ PendingRequestMap::iterator current = it++;
+ if (current->second->context == (*context_iter)->context) {
+ current->second->context.Dispose();
+ current->second->context.Clear();
+ pending_requests.erase(current);
+ }
+ }
+
+ // Remove it from our registered contexts.
+ (*context_iter)->context.ClearWeak();
+ if (!in_gc) {
+ (*context_iter)->context.Dispose();
+ (*context_iter)->context.Clear();
+ }
+
+ GetContexts().erase(context_iter);
+}
+
+static void ContextWeakReferenceCallback(v8::Persistent<v8::Value> context,
+ void*) {
+ // This should only get called for content script contexts.
+ for (ContextList::iterator it = GetContexts().begin();
+ it != GetContexts().end(); ++it) {
+ if ((*it)->context == context) {
+ UnregisterContext(it, true);
+ return;
+ }
+ }
+
+ NOTREACHED();
+}
+
+void EventBindings::HandleContextCreated(
+ WebFrame* frame,
+ v8::Handle<v8::Context> context,
+ ExtensionDispatcher* extension_dispatcher,
+ int isolated_world_id) {
+ if (!bindings_registered)
+ return;
+
+ bool content_script = isolated_world_id != 0;
+ ContextList& contexts = GetContexts();
+
+ v8::Persistent<v8::Context> persistent_context;
+ std::string extension_id;
+
+ if (content_script) {
+ // Content script contexts can get GCed before their frame goes away, so
+ // set up a GC callback.
+ persistent_context = v8::Persistent<v8::Context>::New(context);
+ persistent_context.MakeWeak(NULL, &ContextWeakReferenceCallback);
+ extension_id =
+ extension_dispatcher->user_script_slave()->
+ GetExtensionIdForIsolatedWorld(isolated_world_id);
+ } else {
+ // Figure out the frame's URL. If the frame is loading, use its provisional
+ // URL, since we get this notification before commit.
+ WebDataSource* ds = frame->provisionalDataSource();
+ if (!ds)
+ ds = frame->dataSource();
+ GURL url = ds->request().url();
+ const ExtensionSet* extensions = extension_dispatcher->extensions();
+ extension_id = extensions->GetIdByURL(url);
+
+ if (!extensions->ExtensionBindingsAllowed(url)) {
+ // 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).
+ if (!in_unit_tests)
+ return;
+
+ // For tests, we want the dispatchOnLoad to actually setup our bindings,
+ // so we give a fake extension id;
+ extension_id = kTestingExtensionId;
+ }
+
+ persistent_context = v8::Persistent<v8::Context>::New(context);
+ }
+
+ contexts.push_back(linked_ptr<ContextInfo>(
+ new ContextInfo(persistent_context, extension_id, frame)));
+
+ v8::HandleScope handle_scope;
+ v8::Handle<v8::Value> argv[3];
+ argv[0] = v8::String::New(extension_id.c_str());
+ argv[1] = v8::Boolean::New(extension_dispatcher->is_extension_process());
+ argv[2] = v8::Boolean::New(
+ ChromeRenderProcessObserver::is_incognito_process());
+ CallFunctionInContext(context, "dispatchOnLoad", arraysize(argv), argv);
+}
+
+// static
+void EventBindings::HandleContextDestroyed(WebFrame* frame) {
+ if (!bindings_registered)
+ return;
+
+ v8::HandleScope handle_scope;
+ v8::Local<v8::Context> context = frame->mainWorldScriptContext();
+ if (!context.IsEmpty()) {
+ ContextList::iterator context_iter = bindings_utils::FindContext(context);
+ if (context_iter != GetContexts().end())
+ UnregisterContext(context_iter, false);
+ }
+
+ // Unload any content script contexts for this frame. Note that the frame
+ // itself might not be registered, but can still be a parent frame.
+ for (ContextList::iterator it = GetContexts().begin();
+ it != GetContexts().end(); ) {
+ if ((*it)->unsafe_frame == frame) {
+ UnregisterContext(it, false);
+ // UnregisterContext will remove |it| from the list, but may also
+ // modify the rest of the list as a result of calling into javascript.
+ it = GetContexts().begin();
+ } else {
+ ++it;
+ }
+ }
+}
+
+// static
+void EventBindings::CallFunction(const std::string& extension_id,
+ const std::string& function_name,
+ const ListValue& arguments,
+ RenderView* render_view,
+ const GURL& event_url) {
+ v8::HandleScope handle_scope;
+
+ // We copy the context list, because calling into javascript may modify it
+ // out from under us. We also guard against deleted contexts by checking if
+ // they have been cleared first.
+ ContextList contexts = GetContexts();
+
+ V8ValueConverter converter;
+ for (ContextList::iterator it = contexts.begin();
+ it != contexts.end(); ++it) {
+ if ((*it)->context.IsEmpty())
+ continue;
+
+ if (!extension_id.empty() && extension_id != (*it)->extension_id)
+ continue;
+
+ WebFrame* context_frame = WebFrame::frameForContext((*it)->context);
+ if (!context_frame || !context_frame->view())
+ continue;
+
+ RenderView* context_render_view =
+ RenderView::FromWebView(context_frame->view());
+ if (!context_render_view)
+ continue;
+
+ if (render_view && render_view != context_render_view)
+ continue;
+
+ if (!HasSufficientPermissions(context_render_view, event_url))
+ continue;
+
+ v8::Local<v8::Context> context(*((*it)->context));
+ std::vector<v8::Handle<v8::Value> > v8_arguments;
+ for (size_t i = 0; i < arguments.GetSize(); ++i) {
+ Value* item = NULL;
+ CHECK(arguments.Get(i, &item));
+ v8_arguments.push_back(converter.ToV8Value(item, context));
+ }
+
+ v8::Handle<v8::Value> retval = CallFunctionInContext(
+ context, function_name, v8_arguments.size(), &v8_arguments[0]);
+ // In debug, the js will validate the event parameters and return a
+ // string if a validation error has occured.
+ // TODO(rafaelw): Consider only doing this check if function_name ==
+ // "Event.dispatchJSON".
+#ifndef NDEBUG
+ if (!retval.IsEmpty() && !retval->IsUndefined()) {
+ std::string error = *v8::String::AsciiValue(retval);
+ DCHECK(false) << error;
+ }
+#endif
+ }
+}
diff --git a/chrome/renderer/extensions/event_bindings.h b/chrome/renderer/extensions/event_bindings.h
index 4599217..75deefb 100644
--- a/chrome/renderer/extensions/event_bindings.h
+++ b/chrome/renderer/extensions/event_bindings.h
@@ -6,21 +6,57 @@
#define CHROME_RENDERER_EXTENSIONS_EVENT_BINDINGS_H_
#pragma once
-#include "v8/include/v8.h"
+#include <string>
class ExtensionDispatcher;
+class GURL;
class RenderThreadBase;
+class RenderView;
+
+namespace base {
+class ListValue;
+}
+
+namespace v8 {
+class Context;
+class Extension;
+template <class T> class Handle;
+}
+
+namespace WebKit {
+class WebFrame;
+}
// This class deals with the javascript bindings related to Event objects.
class EventBindings {
public:
static const char* kName; // The v8::Extension name, for dependencies.
+ static const char* kTestingExtensionId;
static v8::Extension* Get(ExtensionDispatcher* dispatcher);
// Allow RenderThread to be mocked out.
static void SetRenderThread(RenderThreadBase* thread);
static RenderThreadBase* GetRenderThread();
+
+ // Handle a script context coming / going away.
+ static void HandleContextCreated(WebKit::WebFrame* frame,
+ v8::Handle<v8::Context> context,
+ ExtensionDispatcher* extension_dispatcher,
+ int isolated_world_id);
+ static void HandleContextDestroyed(WebKit::WebFrame* frame);
+
+ // Calls the given function in each registered context which is listening for
+ // events. If render_view is non-NULL, only call the function in contexts
+ // belonging to that view. See comments on
+ // bindings_utils::CallFunctionInContext for more details.
+ // The called javascript function should not return a value other than
+ // v8::Undefined(). A DCHECK is setup to break if it is otherwise.
+ static void CallFunction(const std::string& extension_id,
+ const std::string& function_name,
+ const base::ListValue& arguments,
+ RenderView* render_view,
+ const GURL& event_url);
};
#endif // CHROME_RENDERER_EXTENSIONS_EVENT_BINDINGS_H_
diff --git a/chrome/renderer/extensions/extension_api_json_validity_unittest.cc b/chrome/renderer/extensions/extension_api_json_validity_unittest.cc
index f382923..3270ec9 100644
--- a/chrome/renderer/extensions/extension_api_json_validity_unittest.cc
+++ b/chrome/renderer/extensions/extension_api_json_validity_unittest.cc
@@ -7,6 +7,7 @@
#include "base/memory/scoped_ptr.h"
#include "base/path_service.h"
#include "chrome/common/chrome_paths.h"
+#include "chrome/renderer/extensions/bindings_utils.h"
#include "chrome/renderer/extensions/extension_base.h"
#include "chrome/test/base/v8_unit_test.h"
#include "content/common/json_value_serializer.h"
diff --git a/chrome/renderer/extensions/extension_base.cc b/chrome/renderer/extensions/extension_base.cc
index 002c3b1..ce66101 100644
--- a/chrome/renderer/extensions/extension_base.cc
+++ b/chrome/renderer/extensions/extension_base.cc
@@ -10,6 +10,7 @@
#include "base/string_util.h"
#include "chrome/common/extensions/extension.h"
#include "chrome/common/extensions/extension_set.h"
+#include "chrome/renderer/extensions/bindings_utils.h"
#include "chrome/renderer/extensions/extension_dispatcher.h"
#include "content/renderer/render_view.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebDocument.h"
@@ -23,12 +24,6 @@ using WebKit::WebView;
namespace {
-const char* kChromeHidden = "chromeHidden";
-
-#ifndef NDEBUG
-const char* kValidateCallbacks = "validateCallbacks";
-#endif
-
typedef std::map<int, std::string> StringMap;
static base::LazyInstance<StringMap> g_string_map(base::LINKER_INITIALIZED);
@@ -108,29 +103,7 @@ v8::Handle<v8::FunctionTemplate>
v8::Handle<v8::Value> ExtensionBase::GetChromeHidden(
const v8::Arguments& args) {
- return GetChromeHidden(v8::Context::GetCurrent());
-}
-
-v8::Handle<v8::Value> ExtensionBase::GetChromeHidden(
- const v8::Handle<v8::Context>& context) {
- v8::Local<v8::Object> global = context->Global();
- v8::Local<v8::Value> hidden = global->GetHiddenValue(
- v8::String::New(kChromeHidden));
-
- if (hidden.IsEmpty() || hidden->IsUndefined()) {
- hidden = v8::Object::New();
- global->SetHiddenValue(v8::String::New(kChromeHidden), hidden);
-
-#ifndef NDEBUG
- // Tell extension_process_bindings.js to validate callbacks and events
- // against their schema definitions in api/extension_api.json.
- v8::Local<v8::Object>::Cast(hidden)
- ->Set(v8::String::New(kValidateCallbacks), v8::True());
-#endif
- }
-
- DCHECK(hidden->IsObject());
- return v8::Local<v8::Object>::Cast(hidden);
+ return bindings_utils::GetChromeHiddenForContext(v8::Context::GetCurrent());
}
v8::Handle<v8::Value> ExtensionBase::Print(const v8::Arguments& args) {
diff --git a/chrome/renderer/extensions/extension_base.h b/chrome/renderer/extensions/extension_base.h
index 9e9efb1..3594f39 100644
--- a/chrome/renderer/extensions/extension_base.h
+++ b/chrome/renderer/extensions/extension_base.h
@@ -43,11 +43,6 @@ class ExtensionBase : public v8::Extension {
// TODO(jstritar): Used for testing http://crbug.com/91582. Remove when done.
ExtensionDispatcher* extension_dispatcher() { return extension_dispatcher_; }
- // Returns a hidden variable for use by the bindings in the specified context
- // that is unreachable by the page for the current context.
- static v8::Handle<v8::Value> GetChromeHidden(
- const v8::Handle<v8::Context>& context);
-
protected:
template<class T>
static T* GetFromArguments(const v8::Arguments& args) {
@@ -70,7 +65,8 @@ class ExtensionBase : public v8::Extension {
bool CheckPermissionForCurrentRenderView(
const std::string& function_name) const;
- // Returns the chromeHidden object for the current context.
+ // Returns a hidden variable for use by the bindings that is unreachable
+ // by the page.
static v8::Handle<v8::Value> GetChromeHidden(const v8::Arguments& args);
ExtensionDispatcher* extension_dispatcher_;
diff --git a/chrome/renderer/extensions/extension_bindings_context.cc b/chrome/renderer/extensions/extension_bindings_context.cc
deleted file mode 100644
index 1d3e1eb..0000000
--- a/chrome/renderer/extensions/extension_bindings_context.cc
+++ /dev/null
@@ -1,235 +0,0 @@
-// 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.
-
-#include "chrome/renderer/extensions/extension_bindings_context.h"
-
-#include <string>
-#include <vector>
-
-#include "base/lazy_instance.h"
-#include "base/logging.h"
-#include "base/memory/linked_ptr.h"
-#include "base/string_split.h"
-#include "base/values.h"
-#include "chrome/common/extensions/extension.h"
-#include "chrome/common/extensions/extension_set.h"
-#include "chrome/renderer/chrome_render_process_observer.h"
-#include "chrome/renderer/extensions/extension_base.h"
-#include "chrome/renderer/extensions/extension_dispatcher.h"
-#include "chrome/renderer/extensions/user_script_slave.h"
-#include "content/common/url_constants.h"
-#include "content/renderer/render_view.h"
-#include "content/renderer/v8_value_converter.h"
-#include "googleurl/src/gurl.h"
-#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/WebURL.h"
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebURLRequest.h"
-#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
-#include "v8/include/v8.h"
-
-namespace {
-
-typedef std::vector<linked_ptr<ExtensionBindingsContext> > ContextList;
-base::LazyInstance<ContextList> g_contexts(base::LINKER_INITIALIZED);
-
-base::LazyInstance<std::string> g_testing_id(base::LINKER_INITIALIZED);
-
-// Returns true if the extension running in the given |render_view| has
-// sufficient permissions to access the data.
-static bool HasSufficientPermissions(RenderView* render_view,
- const GURL& event_url) {
- // During unit tests, we might be invoked without a v8 context. In these
- // cases, we only allow empty event_urls and short-circuit before retrieving
- // the render view from the current context.
- if (!event_url.is_valid())
- return true;
-
- // TODO(aa): This looks super suspicious.
- WebKit::WebDocument document =
- render_view->webview()->mainFrame()->document();
- return GURL(document.url()).SchemeIs(chrome::kExtensionScheme) &&
- document.securityOrigin().canRequest(event_url);
-}
-
-}
-
-void ExtensionBindingsContext::HandleV8ContextCreated(
- WebKit::WebFrame* web_frame,
- const v8::Handle<v8::Context>& v8_context,
- ExtensionDispatcher* extension_dispatcher,
- int isolated_world_id) {
-
- std::string extension_id;
- if (!g_testing_id.Get().empty()) {
- extension_id = g_testing_id.Get();
- } else if (isolated_world_id == 0) {
- // Figure out the frame's URL. If the frame is loading, use its provisional
- // URL, since we get this notification before commit.
- WebKit::WebDataSource* ds = web_frame->provisionalDataSource();
- if (!ds)
- ds = web_frame->dataSource();
- GURL url = ds->request().url();
- const ExtensionSet* extensions = extension_dispatcher->extensions();
- extension_id = extensions->GetIdByURL(url);
-
- if (!extensions->ExtensionBindingsAllowed(url))
- return;
- } else {
- extension_id =
- extension_dispatcher->user_script_slave()->
- GetExtensionIdForIsolatedWorld(isolated_world_id);
- }
-
- ExtensionBindingsContext* instance =
- new ExtensionBindingsContext(v8_context, web_frame, extension_id);
- g_contexts.Pointer()->push_back(
- linked_ptr<ExtensionBindingsContext>(instance));
- VLOG(1) << "Num tracked contexts: " << g_contexts.Pointer()->size();
-
- v8::HandleScope handle_scope;
- v8::Handle<v8::Value> argv[3];
- argv[0] = v8::String::New(extension_id.c_str());
- argv[1] = v8::Boolean::New(extension_dispatcher->is_extension_process());
- argv[2] = v8::Boolean::New(
- ChromeRenderProcessObserver::is_incognito_process());
- instance->CallChromeHiddenMethod("dispatchOnLoad", arraysize(argv), argv);
-}
-
-void ExtensionBindingsContext::HandleV8ContextDestroyed(
- WebKit::WebFrame* web_frame) {
- for (ContextList::iterator iter = g_contexts.Pointer()->begin();
- iter != g_contexts.Pointer()->end();) {
- if ((*iter)->web_frame() == web_frame)
- iter = g_contexts.Pointer()->erase(iter);
- else
- ++iter;
- }
- VLOG(1) << "Num tracked contexts: " << g_contexts.Pointer()->size();
-}
-
-ExtensionBindingsContext* ExtensionBindingsContext::GetCurrent() {
- return GetByV8Context(v8::Context::GetCurrent());
-}
-
-ExtensionBindingsContext* ExtensionBindingsContext::GetByV8Context(
- const v8::Handle<v8::Context>& v8_context) {
- CHECK(!v8_context.IsEmpty());
-
- for (ContextList::iterator iter = g_contexts.Pointer()->begin();
- iter != g_contexts.Pointer()->end(); ++iter) {
- if ((*iter)->v8_context() == v8_context)
- return iter->get();
- }
-
- return NULL;
-}
-
-void ExtensionBindingsContext::DispatchChromeHiddenMethod(
- const std::string& extension_id,
- const std::string& method_name,
- const base::ListValue& arguments,
- RenderView* render_view,
- const GURL& event_url) {
- v8::HandleScope handle_scope;
-
- // We copy the context list, because calling into javascript may modify it
- // out from under us. We also guard against deleted contexts by checking if
- // they have been cleared first.
- ContextList contexts = g_contexts.Get();
-
- V8ValueConverter converter;
- for (ContextList::iterator it = contexts.begin(); it != contexts.end();
- ++it) {
- if ((*it)->v8_context().IsEmpty())
- continue;
-
- if (!extension_id.empty() && extension_id != (*it)->extension_id())
- continue;
-
- if (!(*it)->web_frame()->view())
- continue;
-
- RenderView* context_render_view =
- RenderView::FromWebView((*it)->web_frame()->view());
- if (!context_render_view)
- continue;
-
- if (render_view && render_view != context_render_view)
- continue;
-
- if (!HasSufficientPermissions(context_render_view, event_url))
- continue;
-
- v8::Local<v8::Context> context(*((*it)->v8_context()));
- std::vector<v8::Handle<v8::Value> > v8_arguments;
- for (size_t i = 0; i < arguments.GetSize(); ++i) {
- base::Value* item = NULL;
- CHECK(arguments.Get(i, &item));
- v8_arguments.push_back(converter.ToV8Value(item, context));
- }
-
- v8::Handle<v8::Value> retval = (*it)->CallChromeHiddenMethod(
- method_name, v8_arguments.size(), &v8_arguments[0]);
- // In debug, the js will validate the event parameters and return a
- // string if a validation error has occured.
- // TODO(rafaelw): Consider only doing this check if function_name ==
- // "Event.dispatchJSON".
-#ifndef NDEBUG
- if (!retval.IsEmpty() && !retval->IsUndefined()) {
- std::string error = *v8::String::AsciiValue(retval);
- DCHECK(false) << error;
- }
-#endif
- }
-}
-
-void ExtensionBindingsContext::SetTestExtensionId(const std::string& id) {
- g_testing_id.Get() = id;
-}
-
-ExtensionBindingsContext::ExtensionBindingsContext(
- v8::Handle<v8::Context> v8_context,
- WebKit::WebFrame* web_frame,
- const std::string& extension_id)
- : v8_context_(v8::Persistent<v8::Context>::New(v8_context)),
- web_frame_(web_frame),
- extension_id_(extension_id) {
- VLOG(1) << "Created context for extension\n"
- << " id: " << extension_id << "\n"
- << " frame: " << web_frame_;
-}
-
-ExtensionBindingsContext::~ExtensionBindingsContext() {
- VLOG(1) << "Destroyed context for extension\n"
- << " id: " << extension_id_ << "\n"
- << " frame: " << web_frame_;
- v8::HandleScope handle_scope;
- CallChromeHiddenMethod("dispatchOnUnload", 0, NULL);
- v8_context_.Dispose();
-}
-
-v8::Handle<v8::Value> ExtensionBindingsContext::CallChromeHiddenMethod(
- const std::string& function_name,
- int argc,
- v8::Handle<v8::Value>* argv) {
- v8::Context::Scope context_scope(v8_context_);
-
- // Look up the function name, which may be a sub-property like
- // "Port.dispatchOnMessage" in the hidden global variable.
- v8::Local<v8::Value> value = v8::Local<v8::Value>::New(
- ExtensionBase::GetChromeHidden(v8_context_));
- std::vector<std::string> components;
- base::SplitStringDontTrim(function_name, '.', &components);
- for (size_t i = 0; i < components.size(); ++i) {
- if (!value.IsEmpty()) {
- value = v8::Local<v8::Object>::Cast(value)->Get(
- v8::String::New(components[i].c_str()));
- }
- }
- CHECK(!value.IsEmpty() && value->IsFunction());
- return v8::Local<v8::Function>::Cast(value)->Call(
- v8::Object::New(), argc, argv);
-}
diff --git a/chrome/renderer/extensions/extension_bindings_context.h b/chrome/renderer/extensions/extension_bindings_context.h
deleted file mode 100644
index 44f8b0a..0000000
--- a/chrome/renderer/extensions/extension_bindings_context.h
+++ /dev/null
@@ -1,95 +0,0 @@
-// 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.
-
-#ifndef CHROME_RENDERER_EXTENSIONS_EXTENSION_BINDINGS_CONTEXT_H_
-#define CHROME_RENDERER_EXTENSIONS_EXTENSION_BINDINGS_CONTEXT_H_
-#pragma once
-
-#include <string>
-
-#include "v8/include/v8.h"
-
-namespace base {
-class ListValue;
-}
-
-namespace WebKit {
-class WebFrame;
-}
-
-class ExtensionDispatcher;
-class GURL;
-class RenderView;
-
-// A v8 context that contains extension bindings.
-class ExtensionBindingsContext {
- public:
- static void HandleV8ContextCreated(WebKit::WebFrame* frame,
- const v8::Handle<v8::Context>& v8_context,
- ExtensionDispatcher* extension_dispatcher,
- int isolated_world_id);
-
- static void HandleV8ContextDestroyed(WebKit::WebFrame* frame);
-
- static ExtensionBindingsContext* GetCurrent();
-
- static ExtensionBindingsContext* GetByV8Context(
- const v8::Handle<v8::Context>& v8_context);
-
- // Calls chromeHidden.<methodName> in each context for <extension_id>. If
- // render_view is non-NULL, only call the function in contexts belonging to
- // that view. The called javascript function should not return a value other
- // than v8::Undefined(). A DCHECK is setup to break if it is otherwise.
- static void DispatchChromeHiddenMethod(const std::string& extension_id,
- const std::string& method_name,
- const base::ListValue& arguments,
- RenderView* render_view,
- const GURL& event_url);
-
- static void SetTestExtensionId(const std::string&);
-
- ~ExtensionBindingsContext();
-
- v8::Handle<v8::Context> v8_context() const {
- return v8_context_;
- }
-
- const std::string& extension_id() const {
- return extension_id_;
- }
-
- WebKit::WebFrame* web_frame() const {
- return web_frame_;
- }
-
- // Call the named method of the chromeHidden object in this context.
- // The function can be a sub-property like "Port.dispatchOnMessage". Returns
- // the result of the function call. If an exception is thrown an empty Handle
- // will be returned.
- v8::Handle<v8::Value> CallChromeHiddenMethod(const std::string& function_name,
- int argc,
- v8::Handle<v8::Value>* argv);
-
- private:
- ExtensionBindingsContext(v8::Handle<v8::Context> context,
- WebKit::WebFrame* frame,
- const std::string& extension_id);
-
- // The v8 context the bindings are accessible to. We keep a strong reference
- // to it for simplicity. In the case of content scripts, this is necessary
- // because we want all scripts from the same extension for the same frame to
- // run in the same context, so we can't have the contexts being GC'd if
- // nothing is happening. In the case of page contexts, this isn't necessary
- // since the DOM keeps the context alive, but it makes things simpler to not
- // distinguish the two cases.
- v8::Persistent<v8::Context> v8_context_;
-
- // The WebFrame associated with this context.
- WebKit::WebFrame* web_frame_;
-
- // The extension ID this context is associated with.
- std::string extension_id_;
-};
-
-#endif // CHROME_RENDERER_EXTENSIONS_EXTENSION_BINDINGS_CONTEXT_H_
diff --git a/chrome/renderer/extensions/extension_dispatcher.cc b/chrome/renderer/extensions/extension_dispatcher.cc
index 5baa8d4..d2f06ef 100644
--- a/chrome/renderer/extensions/extension_dispatcher.cc
+++ b/chrome/renderer/extensions/extension_dispatcher.cc
@@ -14,7 +14,6 @@
#include "chrome/renderer/extensions/chrome_app_bindings.h"
#include "chrome/renderer/extensions/chrome_webstore_bindings.h"
#include "chrome/renderer/extensions/event_bindings.h"
-#include "chrome/renderer/extensions/extension_bindings_context.h"
#include "chrome/renderer/extensions/extension_groups.h"
#include "chrome/renderer/extensions/extension_process_bindings.h"
#include "chrome/renderer/extensions/js_only_v8_extensions.h"
@@ -136,7 +135,7 @@ void ExtensionDispatcher::OnMessageInvoke(const std::string& extension_id,
const std::string& function_name,
const ListValue& args,
const GURL& event_url) {
- ExtensionBindingsContext::DispatchChromeHiddenMethod(
+ EventBindings::CallFunction(
extension_id, function_name, args, NULL, event_url);
// Reset the idle handler each time there's any activity like event or message
diff --git a/chrome/renderer/extensions/extension_helper.cc b/chrome/renderer/extensions/extension_helper.cc
index e1a1e27..a3df162c 100644
--- a/chrome/renderer/extensions/extension_helper.cc
+++ b/chrome/renderer/extensions/extension_helper.cc
@@ -13,7 +13,6 @@
#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
#include "chrome/renderer/extensions/event_bindings.h"
-#include "chrome/renderer/extensions/extension_bindings_context.h"
#include "chrome/renderer/extensions/extension_dispatcher.h"
#include "chrome/renderer/extensions/extension_process_bindings.h"
#include "chrome/renderer/extensions/user_script_idle_scheduler.h"
@@ -204,7 +203,7 @@ void ExtensionHelper::OnExtensionMessageInvoke(const std::string& extension_id,
const std::string& function_name,
const ListValue& args,
const GURL& event_url) {
- ExtensionBindingsContext::DispatchChromeHiddenMethod(
+ EventBindings::CallFunction(
extension_id, function_name, args, render_view(), event_url);
}
diff --git a/chrome/renderer/extensions/extension_process_bindings.cc b/chrome/renderer/extensions/extension_process_bindings.cc
index 9cdc396..128375b 100644
--- a/chrome/renderer/extensions/extension_process_bindings.cc
+++ b/chrome/renderer/extensions/extension_process_bindings.cc
@@ -4,7 +4,6 @@
#include "chrome/renderer/extensions/extension_process_bindings.h"
-#include <map>
#include <set>
#include <string>
#include <vector>
@@ -12,7 +11,6 @@
#include "base/callback.h"
#include "base/command_line.h"
#include "base/json/json_reader.h"
-#include "base/lazy_instance.h"
#include "base/memory/scoped_ptr.h"
#include "base/string_number_conversions.h"
#include "base/string_util.h"
@@ -25,8 +23,8 @@
#include "chrome/common/render_messages.h"
#include "chrome/common/url_constants.h"
#include "chrome/renderer/chrome_render_process_observer.h"
+#include "chrome/renderer/extensions/bindings_utils.h"
#include "chrome/renderer/extensions/event_bindings.h"
-#include "chrome/renderer/extensions/extension_bindings_context.h"
#include "chrome/renderer/extensions/extension_base.h"
#include "chrome/renderer/extensions/extension_dispatcher.h"
#include "chrome/renderer/extensions/extension_helper.h"
@@ -44,6 +42,9 @@
#include "third_party/skia/include/core/SkColor.h"
#include "webkit/glue/webkit_glue.h"
+using bindings_utils::GetPendingRequestMap;
+using bindings_utils::PendingRequest;
+using bindings_utils::PendingRequestMap;
using WebKit::WebFrame;
using WebKit::WebView;
@@ -57,20 +58,6 @@ const char* kExtensionDeps[] = {
ExtensionApiTestV8Extension::kName,
};
-// Contains info relevant to a pending API request.
-struct PendingRequest {
- public :
- PendingRequest(v8::Persistent<v8::Context> context, const std::string& name)
- : context(context), name(name) {
- }
- v8::Persistent<v8::Context> context;
- std::string name;
-};
-typedef std::map<int, linked_ptr<PendingRequest> > PendingRequestMap;
-
-base::LazyInstance<PendingRequestMap> g_pending_requests(
- base::LINKER_INITIALIZED);
-
// A RenderViewVisitor class that iterates through the set of available
// views, looking for a view of the given type, in the given browser window
// and within the given extension.
@@ -442,7 +429,7 @@ class ExtensionImpl : public ExtensionBase {
v8::Persistent<v8::Context> current_context =
v8::Persistent<v8::Context>::New(v8::Context::GetCurrent());
DCHECK(!current_context.IsEmpty());
- g_pending_requests.Get()[request_id].reset(new PendingRequest(
+ GetPendingRequestMap()[request_id].reset(new PendingRequest(
current_context, name));
ExtensionHostMsg_Request_Params params;
@@ -573,9 +560,9 @@ v8::Extension* ExtensionProcessBindings::Get(
void ExtensionProcessBindings::HandleResponse(int request_id, bool success,
const std::string& response,
const std::string& error) {
- PendingRequestMap::iterator request =
- g_pending_requests.Get().find(request_id);
- if (request == g_pending_requests.Get().end())
+ PendingRequestMap& pending_requests = GetPendingRequestMap();
+ PendingRequestMap::iterator request = pending_requests.find(request_id);
+ if (request == pending_requests.end())
return; // The frame went away.
v8::HandleScope handle_scope;
@@ -585,12 +572,8 @@ void ExtensionProcessBindings::HandleResponse(int request_id, bool success,
argv[2] = v8::Boolean::New(success);
argv[3] = v8::String::New(response.c_str());
argv[4] = v8::String::New(error.c_str());
- ExtensionBindingsContext* bindings_context =
- ExtensionBindingsContext::GetByV8Context(request->second->context);
- v8::Handle<v8::Value> retval =
- bindings_context->CallChromeHiddenMethod("handleResponse",
- arraysize(argv),
- argv);
+ v8::Handle<v8::Value> retval = bindings_utils::CallFunctionInContext(
+ request->second->context, "handleResponse", arraysize(argv), argv);
// In debug, the js will validate the callback parameters and return a
// string if a validation error has occured.
#ifndef NDEBUG
@@ -602,5 +585,5 @@ void ExtensionProcessBindings::HandleResponse(int request_id, bool success,
request->second->context.Dispose();
request->second->context.Clear();
- g_pending_requests.Get().erase(request);
+ pending_requests.erase(request);
}
diff --git a/chrome/renderer/extensions/renderer_extension_bindings.cc b/chrome/renderer/extensions/renderer_extension_bindings.cc
index cb0e8be..3e4b25d 100644
--- a/chrome/renderer/extensions/renderer_extension_bindings.cc
+++ b/chrome/renderer/extensions/renderer_extension_bindings.cc
@@ -12,6 +12,7 @@
#include "chrome/common/extensions/extension_message_bundle.h"
#include "chrome/common/extensions/extension_messages.h"
#include "chrome/common/url_constants.h"
+#include "chrome/renderer/extensions/bindings_utils.h"
#include "chrome/renderer/extensions/event_bindings.h"
#include "chrome/renderer/extensions/extension_base.h"
#include "chrome/renderer/extensions/extension_dispatcher.h"