summaryrefslogtreecommitdiffstats
path: root/chrome
diff options
context:
space:
mode:
Diffstat (limited to 'chrome')
-rw-r--r--chrome/browser/extensions/extension_message_service.cc52
-rw-r--r--chrome/browser/extensions/extension_message_service.h40
-rw-r--r--chrome/browser/extensions/extension_messages_unittest.cc28
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.cc5
-rw-r--r--chrome/browser/renderer_host/resource_message_filter.h4
-rw-r--r--chrome/common/render_messages_internal.h10
-rw-r--r--chrome/renderer/extensions/renderer_extension_bindings.cc5
-rw-r--r--chrome/renderer/mock_render_thread.cc5
-rw-r--r--chrome/renderer/mock_render_thread.h6
-rw-r--r--chrome/renderer/renderer_resources.grd2
-rw-r--r--chrome/renderer/resources/extension_process_bindings.js3
-rw-r--r--chrome/renderer/resources/renderer_extension_bindings.js25
12 files changed, 118 insertions, 67 deletions
diff --git a/chrome/browser/extensions/extension_message_service.cc b/chrome/browser/extensions/extension_message_service.cc
index 78dd1f2..70bfda7 100644
--- a/chrome/browser/extensions/extension_message_service.cc
+++ b/chrome/browser/extensions/extension_message_service.cc
@@ -42,13 +42,15 @@ struct SingletonData {
InstanceMap map;
};
-static void DispatchOnConnect(IPC::Message::Sender* channel, int source_port_id,
+static void DispatchOnConnect(IPC::Message::Sender* channel, int dest_port_id,
+ const std::string& channel_name,
const std::string& tab_json,
const std::string& extension_id) {
ListValue args;
- args.Set(0, Value::CreateIntegerValue(source_port_id));
- args.Set(1, Value::CreateStringValue(tab_json));
- args.Set(2, Value::CreateStringValue(extension_id));
+ args.Set(0, Value::CreateIntegerValue(dest_port_id));
+ args.Set(1, Value::CreateStringValue(channel_name));
+ args.Set(2, Value::CreateStringValue(tab_json));
+ args.Set(3, Value::CreateStringValue(extension_id));
channel->Send(new ViewMsg_ExtensionMessageInvoke(
ExtensionMessageService::kDispatchOnConnect, args));
}
@@ -172,7 +174,7 @@ void ExtensionMessageService::AllocatePortIdPair(int* port1, int* port2) {
int ExtensionMessageService::OpenChannelToExtension(
int routing_id, const std::string& extension_id,
- ResourceMessageFilter* source) {
+ const std::string& channel_name, ResourceMessageFilter* source) {
DCHECK_EQ(MessageLoop::current(),
ChromeThread::GetMessageLoop(ChromeThread::IO));
DCHECK(initialized_);
@@ -182,24 +184,29 @@ int ExtensionMessageService::OpenChannelToExtension(
int port2_id = -1;
AllocatePortIdPair(&port1_id, &port2_id);
+ // Each side of the port is given his own port ID. When they send messages,
+ // we convert to the opposite port ID. See PostMessageFromRenderer.
ui_loop_->PostTask(FROM_HERE,
NewRunnableMethod(this, &ExtensionMessageService::OpenChannelOnUIThread,
- routing_id, port1_id, source->GetProcessId(), extension_id));
+ routing_id, port2_id, source->GetProcessId(), extension_id,
+ channel_name));
- return port2_id;
+ return port1_id;
}
void ExtensionMessageService::OpenChannelOnUIThread(
- int source_routing_id, int source_port_id, int source_process_id,
- const std::string& extension_id) {
+ int source_routing_id, int receivers_port_id, int source_process_id,
+ const std::string& extension_id, const std::string& channel_name) {
RenderProcessHost* source = RenderProcessHost::FromID(source_process_id);
- OpenChannelOnUIThreadImpl(source_routing_id, source_port_id,
- source_process_id, source, extension_id);
+ OpenChannelOnUIThreadImpl(source_routing_id, receivers_port_id,
+ source_process_id, source, extension_id,
+ channel_name);
}
void ExtensionMessageService::OpenChannelOnUIThreadImpl(
- int source_routing_id, int source_port_id, int source_process_id,
- IPC::Message::Sender* source, const std::string& extension_id) {
+ int source_routing_id, int receivers_port_id, int source_process_id,
+ IPC::Message::Sender* source, const std::string& extension_id,
+ const std::string& channel_name) {
DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI);
if (!source)
@@ -224,7 +231,7 @@ void ExtensionMessageService::OpenChannelOnUIThreadImpl(
return;
}
- channels_[GET_CHANNEL_ID(source_port_id)] = channel;
+ channels_[GET_CHANNEL_ID(receivers_port_id)] = channel;
// Include info about the opener's tab (if it was a tab).
std::string tab_json = "null";
@@ -239,7 +246,8 @@ void ExtensionMessageService::OpenChannelOnUIThreadImpl(
// port ID (the opener has the opposite port ID).
for (MessageChannel::Ports::iterator it = channel->receivers.begin();
it != channel->receivers.end(); ++it) {
- DispatchOnConnect(*it, source_port_id, tab_json, extension_id);
+ DispatchOnConnect(*it, receivers_port_id, channel_name, tab_json,
+ extension_id);
}
}
@@ -259,10 +267,10 @@ int ExtensionMessageService::OpenAutomationChannelToExtension(
// This isn't really appropriate here, the originating tab
// information should be supplied by the caller for
// automation-initiated ports.
- OpenChannelOnUIThreadImpl(routing_id, port1_id, source_process_id,
- source, extension_id);
+ OpenChannelOnUIThreadImpl(routing_id, port2_id, source_process_id,
+ source, extension_id, "");
- return port2_id;
+ return port1_id;
}
void ExtensionMessageService::CloseChannel(int port_id) {
@@ -292,23 +300,23 @@ void ExtensionMessageService::CloseChannelImpl(
}
void ExtensionMessageService::PostMessageFromRenderer(
- int dest_port_id, const std::string& message) {
+ int source_port_id, const std::string& message) {
DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI);
MessageChannelMap::iterator iter =
- channels_.find(GET_CHANNEL_ID(dest_port_id));
+ channels_.find(GET_CHANNEL_ID(source_port_id));
if (iter == channels_.end())
return;
// Figure out which port the ID corresponds to.
+ int dest_port_id = GET_OPPOSITE_PORT_ID(source_port_id);
MessageChannel::Ports* ports =
IS_OPENER_PORT_ID(dest_port_id) ?
&iter->second->opener : &iter->second->receivers;
- int source_port_id = GET_OPPOSITE_PORT_ID(dest_port_id);
for (MessageChannel::Ports::iterator it = ports->begin();
it != ports->end(); ++it) {
- DispatchOnMessage(*it, message, source_port_id);
+ DispatchOnMessage(*it, message, dest_port_id);
}
}
diff --git a/chrome/browser/extensions/extension_message_service.h b/chrome/browser/extensions/extension_message_service.h
index 7a87adf..77970bc 100644
--- a/chrome/browser/extensions/extension_message_service.h
+++ b/chrome/browser/extensions/extension_message_service.h
@@ -19,15 +19,27 @@ class RenderProcessHost;
class ResourceMessageFilter;
class URLRequestContext;
-// This class manages message passing between renderer processes. It maintains
-// a list of available extensions and which renderers each lives in, as well as
-// a set of open channels.
+// This class manages message and event passing between renderer processes.
+// It maintains a list of processes that are listening to events (including
+// messaging events), as well as a set of open channels.
+//
+// Messaging works this way:
+// - An extension-owned script context (like a toolstrip or a content script)
+// adds an event listener to the "onConnect" event. We keep track here of a
+// list of "listeners" that registered interest in receiving extension
+// messages.
+// - Another context calls "connect()" to open a channel to every listener
+// owned by the same extension. This is a broadcast event, so every listener
+// will get notified.
+// - Once the channel is established, either side can call postMessage to send
+// a message to the opposite side of the channel, which may have multiple
+// listeners.
//
// Terminology:
-// channel: connection between two ports (one of which belongs to an extension)
-// port: an IPC::Message::Sender interface through which we communicate to a
-// process. We use MessageFilters for this since that allows us to send our
-// messages on the IO thread.
+// channel: connection between two ports (one side of which can have multiple
+// listeners)
+// port: one or more IPC::Message::Sender interfaces through which we
+// communicate to process(es). These are generally RenderProcessHosts.
class ExtensionMessageService : public NotificationObserver {
public:
// Javascript function name constants.
@@ -35,6 +47,7 @@ class ExtensionMessageService : public NotificationObserver {
static const char kDispatchOnDisconnect[];
static const char kDispatchOnMessage[];
static const char kDispatchEvent[];
+ static const char kDispatchError[];
// Returns the message service for the given context. Messages can only
// be sent within a single context.
@@ -78,11 +91,13 @@ class ExtensionMessageService : public NotificationObserver {
// --- IO thread only:
// Given an extension's ID, opens a channel between the given renderer "port"
- // and that extension. Returns a channel ID to be used for posting messages
- // between the processes, or -1 if the extension doesn't exist.
+ // and every listening context owned by that extension. Returns a port ID
+ // to be used for posting messages between the processes. |channel_name| is
+ // an optional identifier for use by extension developers.
// This runs on the IO thread so that it can be used in a synchronous IPC
// message.
int OpenChannelToExtension(int routing_id, const std::string& extension_id,
+ const std::string& channel_name,
ResourceMessageFilter* source);
private:
@@ -110,16 +125,17 @@ class ExtensionMessageService : public NotificationObserver {
// --- UI thread only:
- // Handles channel creation and notifies the destination that a channel was
+ // Handles channel creation and notifies the destinations that a channel was
// opened.
void OpenChannelOnUIThread(int source_routing_id,
int source_port_id, int source_process_id,
- const std::string& extension_id);
+ const std::string& extension_id, const std::string& channel_name);
// Common between OpenChannelOnUIThread and OpenAutomationChannelToExtension.
void OpenChannelOnUIThreadImpl(
int source_routing_id, int source_port_id, int source_process_id,
- IPC::Message::Sender* source, const std::string& extension_id);
+ IPC::Message::Sender* source, const std::string& extension_id,
+ const std::string& channel_name);
NotificationRegistrar registrar_;
diff --git a/chrome/browser/extensions/extension_messages_unittest.cc b/chrome/browser/extensions/extension_messages_unittest.cc
index 27a5bd9..c2e4540 100644
--- a/chrome/browser/extensions/extension_messages_unittest.cc
+++ b/chrome/browser/extensions/extension_messages_unittest.cc
@@ -9,11 +9,13 @@
#include "chrome/test/render_view_test.h"
#include "testing/gtest/include/gtest/gtest.h"
-static void DispatchOnConnect(int source_port_id, const std::string& tab_json) {
+static void DispatchOnConnect(int source_port_id, const std::string& name,
+ const std::string& tab_json) {
ListValue args;
args.Set(0, Value::CreateIntegerValue(source_port_id));
- args.Set(1, Value::CreateStringValue(tab_json));
- args.Set(2, Value::CreateStringValue("")); // extension ID is empty for tests
+ args.Set(1, Value::CreateStringValue(name));
+ args.Set(2, Value::CreateStringValue(tab_json));
+ args.Set(3, Value::CreateStringValue("")); // extension ID is empty for tests
RendererExtensionBindings::Invoke(
ExtensionMessageService::kDispatchOnConnect, args);
}
@@ -40,7 +42,7 @@ TEST_F(RenderViewTest, ExtensionMessagesOpenChannel) {
LoadHTML("<body></body>");
ExecuteJavaScript(
"var e = new chrome.Extension('foobar');"
- "var port = e.connect();"
+ "var port = e.connect('testName');"
"port.onMessage.addListener(doOnMessage);"
"port.postMessage({message: 'content ready'});"
"function doOnMessage(msg, port) {"
@@ -51,7 +53,11 @@ TEST_F(RenderViewTest, ExtensionMessagesOpenChannel) {
const IPC::Message* open_channel_msg =
render_thread_.sink().GetUniqueMessageMatching(
ViewHostMsg_OpenChannelToExtension::ID);
- EXPECT_TRUE(open_channel_msg);
+ ASSERT_TRUE(open_channel_msg);
+ void* iter = IPC::SyncMessage::GetDataIterator(open_channel_msg);
+ ViewHostMsg_OpenChannelToExtension::SendParam open_params;
+ ASSERT_TRUE(IPC::ReadParam(open_channel_msg, &iter, &open_params));
+ EXPECT_EQ("testName", open_params.c);
const IPC::Message* post_msg =
render_thread_.sink().GetUniqueMessageMatching(
@@ -71,7 +77,7 @@ TEST_F(RenderViewTest, ExtensionMessagesOpenChannel) {
render_thread_.sink().GetUniqueMessageMatching(
ViewHostMsg_RunJavaScriptMessage::ID);
ASSERT_TRUE(alert_msg);
- void* iter = IPC::SyncMessage::GetDataIterator(alert_msg);
+ iter = IPC::SyncMessage::GetDataIterator(alert_msg);
ViewHostMsg_RunJavaScriptMessage::SendParam alert_param;
ASSERT_TRUE(IPC::ReadParam(alert_msg, &iter, &alert_param));
EXPECT_EQ(L"content got: 42", alert_param.a);
@@ -86,7 +92,8 @@ TEST_F(RenderViewTest, ExtensionMessagesOnConnect) {
" port.test = 24;"
" port.onMessage.addListener(doOnMessage);"
" port.onDisconnect.addListener(doOnDisconnect);"
- " port.postMessage({message: 'onconnect from ' + port.tab.url});"
+ " port.postMessage({message: 'onconnect from ' + port.tab.url + "
+ " ' name ' + port.name});"
"});"
"function doOnMessage(msg, port) {"
" alert('got: ' + msg.val);"
@@ -99,7 +106,8 @@ TEST_F(RenderViewTest, ExtensionMessagesOnConnect) {
// Simulate a new connection being opened.
const int kPortId = 0;
- DispatchOnConnect(kPortId, "{\"url\":\"foo://bar\"}");
+ const std::string kPortName = "testName";
+ DispatchOnConnect(kPortId, kPortName, "{\"url\":\"foo://bar\"}");
// Verify that we handled the new connection by posting a message.
const IPC::Message* post_msg =
@@ -108,7 +116,9 @@ TEST_F(RenderViewTest, ExtensionMessagesOnConnect) {
ASSERT_TRUE(post_msg);
ViewHostMsg_ExtensionPostMessage::Param post_params;
ViewHostMsg_ExtensionPostMessage::Read(post_msg, &post_params);
- EXPECT_EQ("{\"message\":\"onconnect from foo://bar\"}", post_params.b);
+ std::string expected_msg =
+ "{\"message\":\"onconnect from foo://bar name " + kPortName + "\"}";
+ EXPECT_EQ(expected_msg, post_params.b);
// Now simulate getting a message back from the channel opener.
render_thread_.sink().ClearMessages();
diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc
index 6858430..d913aec 100644
--- a/chrome/browser/renderer_host/resource_message_filter.cc
+++ b/chrome/browser/renderer_host/resource_message_filter.cc
@@ -884,9 +884,10 @@ void ResourceMessageFilter::OnFreeTransportDIB(
#endif
void ResourceMessageFilter::OnOpenChannelToExtension(
- int routing_id, const std::string& extension_id, int* port_id) {
+ int routing_id, const std::string& extension_id,
+ const std::string& channel_name, int* port_id) {
*port_id = ExtensionMessageService::GetInstance(request_context_.get())->
- OpenChannelToExtension(routing_id, extension_id, this);
+ OpenChannelToExtension(routing_id, extension_id, channel_name, this);
}
bool ResourceMessageFilter::CheckBenchmarkingEnabled() {
diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h
index 70eeaf8..613dd77 100644
--- a/chrome/browser/renderer_host/resource_message_filter.h
+++ b/chrome/browser/renderer_host/resource_message_filter.h
@@ -218,8 +218,8 @@ class ResourceMessageFilter : public IPC::ChannelProxy::MessageFilter,
TransportDIB::Handle* result);
void OnFreeTransportDIB(TransportDIB::Id dib_id);
- void OnOpenChannelToExtension(int routing_id,
- const std::string& extension_id, int* port_id);
+ void OnOpenChannelToExtension(int routing_id, const std::string& extension_id,
+ const std::string& channel_name, int* port_id);
void OnCloseIdleConnections();
void OnSetCacheMode(bool enabled);
diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h
index ee3d154..31670ba 100644
--- a/chrome/common/render_messages_internal.h
+++ b/chrome/common/render_messages_internal.h
@@ -1403,12 +1403,14 @@ IPC_BEGIN_MESSAGES(ViewHost)
IPC_MESSAGE_CONTROL1(ViewHostMsg_ForwardToWorker,
IPC::Message /* message */)
- // Get a port handle to a currently-running extension process for the
- // extension with the given ID. If no such extension is found, -1 is
- // returned. The handle can be used for sending messages to the extension.
- IPC_SYNC_MESSAGE_CONTROL2_1(ViewHostMsg_OpenChannelToExtension,
+ // Open a channel to all listening contexts owned by the extension with
+ // the given ID. This always returns a valid port ID which can be used for
+ // sending messages. If an error occurred, the opener will be notified
+ // asynchronously.
+ IPC_SYNC_MESSAGE_CONTROL3_1(ViewHostMsg_OpenChannelToExtension,
int /* routing_id */,
std::string /* extension_id */,
+ std::string /* channel_name */,
int /* port_id */)
// Get a port handle to the given tab's process. The handle can be used for
diff --git a/chrome/renderer/extensions/renderer_extension_bindings.cc b/chrome/renderer/extensions/renderer_extension_bindings.cc
index 4cff1dd..37767f3 100644
--- a/chrome/renderer/extensions/renderer_extension_bindings.cc
+++ b/chrome/renderer/extensions/renderer_extension_bindings.cc
@@ -61,11 +61,12 @@ class ExtensionImpl : public ExtensionBase {
if (!renderview)
return v8::Undefined();
- if (args.Length() >= 1 && args[0]->IsString()) {
+ if (args.Length() >= 2 && args[0]->IsString() && args[1]->IsString()) {
std::string id = *v8::String::Utf8Value(args[0]->ToString());
+ std::string channel_name = *v8::String::Utf8Value(args[1]->ToString());
int port_id = -1;
renderview->Send(new ViewHostMsg_OpenChannelToExtension(
- renderview->routing_id(), id, &port_id));
+ renderview->routing_id(), id, channel_name, &port_id));
return v8::Integer::New(port_id);
}
return v8::Undefined();
diff --git a/chrome/renderer/mock_render_thread.cc b/chrome/renderer/mock_render_thread.cc
index 3494b12..17dab52 100644
--- a/chrome/renderer/mock_render_thread.cc
+++ b/chrome/renderer/mock_render_thread.cc
@@ -97,8 +97,9 @@ void MockRenderThread::OnMsgCreateWidget(int opener_id,
}
void MockRenderThread::OnMsgOpenChannelToExtension(
- int routing_id, const std::string& extension_id, int* channel_id) {
- *channel_id = 0;
+ int routing_id, const std::string& extension_id,
+ const std::string& channel_name, int* port_id) {
+ *port_id = 0;
}
void MockRenderThread::OnDuplicateSection(
diff --git a/chrome/renderer/mock_render_thread.h b/chrome/renderer/mock_render_thread.h
index 1921fb1..0e5bab8 100644
--- a/chrome/renderer/mock_render_thread.h
+++ b/chrome/renderer/mock_render_thread.h
@@ -79,9 +79,9 @@ class MockRenderThread : public RenderThreadBase {
int* route_id);
// The callee expects to be returned a valid channel_id.
- void OnMsgOpenChannelToExtension(int routing_id,
- const std::string& extension_id,
- int* channel_id);
+ void OnMsgOpenChannelToExtension(
+ int routing_id, const std::string& extension_id,
+ const std::string& channel_name, int* port_id);
void OnDuplicateSection(base::SharedMemoryHandle renderer_handle,
base::SharedMemoryHandle* browser_handle);
diff --git a/chrome/renderer/renderer_resources.grd b/chrome/renderer/renderer_resources.grd
index 8acec84..bdba06d 100644
--- a/chrome/renderer/renderer_resources.grd
+++ b/chrome/renderer/renderer_resources.grd
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- This comment is only here because changes to resources are not picked up
-without changes to the corresponding grd file. mp13 -->
+without changes to the corresponding grd file. mp1 -->
<grit latest_public_release="0" current_release="1">
<outputs>
<output filename="grit/renderer_resources.h" type="rc_header">
diff --git a/chrome/renderer/resources/extension_process_bindings.js b/chrome/renderer/resources/extension_process_bindings.js
index 51756d0..1c8fc9c4 100644
--- a/chrome/renderer/resources/extension_process_bindings.js
+++ b/chrome/renderer/resources/extension_process_bindings.js
@@ -7,6 +7,9 @@
// have your change take effect.
// -----------------------------------------------------------------------------
+// This script contains privileged chrome extension related javascript APIs.
+// It is loaded by pages whose URL has the chrome-extension protocol.
+
var chrome = chrome || {};
(function() {
native function GetViews();
diff --git a/chrome/renderer/resources/renderer_extension_bindings.js b/chrome/renderer/resources/renderer_extension_bindings.js
index 2a41d5f..d8b5a4b 100644
--- a/chrome/renderer/resources/renderer_extension_bindings.js
+++ b/chrome/renderer/resources/renderer_extension_bindings.js
@@ -7,6 +7,13 @@
// have your change take effect.
// -----------------------------------------------------------------------------
+// This script contains unprivileged javascript APIs related to chrome
+// extensions. It is loaded by any extension-related context, such as content
+// scripts or toolstrips.
+// See user_script_slave.cc for script that is loaded by content scripts only.
+// TODO(mpcomplete): we also load this in regular web pages, but don't need
+// to.
+
var chrome = chrome || {};
(function () {
native function OpenChannelToExtension(id);
@@ -21,8 +28,9 @@ var chrome = chrome || {};
// Port object. Represents a connection to another script context through
// which messages can be passed.
- chrome.Port = function(portId) {
+ chrome.Port = function(portId, opt_name) {
this.portId_ = portId;
+ this.name = opt_name;
this.onDisconnect = new chrome.Event();
this.onMessage = new chrome.Event();
};
@@ -31,11 +39,11 @@ var chrome = chrome || {};
// Hidden port creation function. We don't want to expose an API that lets
// people add arbitrary port IDs to the port list.
- chromeHidden.Port.createPort = function(portId) {
+ chromeHidden.Port.createPort = function(portId, opt_name) {
if (ports[portId]) {
throw new Error("Port '" + portId + "' already exists.");
}
- var port = new chrome.Port(portId);
+ var port = new chrome.Port(portId, opt_name);
ports[portId] = port;
chromeHidden.onUnload.addListener(function() {
port.disconnect();
@@ -44,14 +52,15 @@ var chrome = chrome || {};
}
// Called by native code when a channel has been opened to this context.
- chromeHidden.Port.dispatchOnConnect = function(portId, tab, extensionId) {
+ chromeHidden.Port.dispatchOnConnect = function(portId, channelName, tab,
+ extensionId) {
// Only create a new Port if someone is actually listening for a connection.
// In addition to being an optimization, this also fixes a bug where if 2
// channels were opened to and from the same process, closing one would
// close both.
var connectEvent = "channel-connect:" + extensionId;
if (chromeHidden.Event.hasListener(connectEvent)) {
- var port = chromeHidden.Port.createPort(portId);
+ var port = chromeHidden.Port.createPort(portId, channelName);
if (tab) {
tab = JSON.parse(tab);
}
@@ -103,11 +112,11 @@ var chrome = chrome || {};
// Opens a message channel to the extension. Returns a Port for
// message passing.
- chrome.Extension.prototype.connect = function() {
- var portId = OpenChannelToExtension(this.id_);
+ chrome.Extension.prototype.connect = function(opt_name) {
+ var portId = OpenChannelToExtension(this.id_, opt_name || "");
if (portId == -1)
throw new Error("No such extension: '" + this.id_ + "'");
- return chromeHidden.Port.createPort(portId);
+ return chromeHidden.Port.createPort(portId, opt_name);
};
// Returns a resource URL that can be used to fetch a resource from this