diff options
Diffstat (limited to 'chrome')
20 files changed, 376 insertions, 94 deletions
diff --git a/chrome/browser/extensions/extension_message_service.cc b/chrome/browser/extensions/extension_message_service.cc index d23576bc..66587b7 100644 --- a/chrome/browser/extensions/extension_message_service.cc +++ b/chrome/browser/extensions/extension_message_service.cc @@ -60,12 +60,14 @@ static void DispatchOnConnect(const ExtensionMessageService::MessagePort& port, int dest_port_id, const std::string& channel_name, const std::string& tab_json, - const std::string& extension_id) { + const std::string& source_extension_id, + const std::string& target_extension_id) { ListValue args; 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)); + args.Set(3, Value::CreateStringValue(source_extension_id)); + args.Set(4, Value::CreateStringValue(target_extension_id)); CHECK(port.sender); port.sender->Send(new ViewMsg_ExtensionMessageInvoke( port.routing_id, ExtensionMessageService::kDispatchOnConnect, args)); @@ -193,7 +195,8 @@ void ExtensionMessageService::AllocatePortIdPair(int* port1, int* port2) { } int ExtensionMessageService::OpenChannelToExtension( - int routing_id, const std::string& extension_id, + int routing_id, const std::string& source_extension_id, + const std::string& target_extension_id, const std::string& channel_name, ResourceMessageFilter* source) { DCHECK_EQ(MessageLoop::current(), ChromeThread::GetMessageLoop(ChromeThread::IO)); @@ -208,7 +211,8 @@ int ExtensionMessageService::OpenChannelToExtension( ui_loop_->PostTask(FROM_HERE, NewRunnableMethod(this, &ExtensionMessageService::OpenChannelToExtensionOnUIThread, - source->id(), routing_id, port2_id, extension_id, channel_name)); + source->id(), routing_id, port2_id, source_extension_id, + target_extension_id, channel_name)); return port1_id; } @@ -239,20 +243,24 @@ int ExtensionMessageService::OpenChannelToTab(int routing_id, void ExtensionMessageService::OpenChannelToExtensionOnUIThread( int source_process_id, int source_routing_id, int receiver_port_id, - const std::string& extension_id, const std::string& channel_name) { + const std::string& source_extension_id, + const std::string& target_extension_id, + const std::string& channel_name) { if (!profile_) return; RenderProcessHost* source = RenderProcessHost::FromID(source_process_id); MessagePort receiver( - profile_->GetExtensionProcessManager()->GetExtensionProcess(extension_id), + profile_->GetExtensionProcessManager()->GetExtensionProcess( + target_extension_id), MSG_ROUTING_CONTROL); receiver.debug_info = 1; TabContents* source_contents = tab_util::GetTabContentsByID( source_process_id, source_routing_id); OpenChannelOnUIThreadImpl(source, source_contents, receiver, receiver_port_id, - extension_id, channel_name); + source_extension_id, target_extension_id, + channel_name); } void ExtensionMessageService::OpenChannelToTabOnUIThread( @@ -273,13 +281,15 @@ void ExtensionMessageService::OpenChannelToTabOnUIThread( source_process_id, source_routing_id); OpenChannelOnUIThreadImpl(source, source_contents, receiver, receiver_port_id, - extension_id, channel_name); + extension_id, extension_id, channel_name); } bool ExtensionMessageService::OpenChannelOnUIThreadImpl( IPC::Message::Sender* source, TabContents* source_contents, const MessagePort& receiver, int receiver_port_id, - const std::string& extension_id, const std::string& channel_name) { + const std::string& source_extension_id, + const std::string& target_extension_id, + const std::string& channel_name) { DCHECK_EQ(MessageLoop::current()->type(), MessageLoop::TYPE_UI); // TODO(mpcomplete): notify source if reciever doesn't exist @@ -320,7 +330,7 @@ bool ExtensionMessageService::OpenChannelOnUIThreadImpl( // Send the connect event to the receiver. Give it the opener's port ID (the // opener has the opposite port ID). DispatchOnConnect(receiver, receiver_port_id, channel_name, tab_json, - extension_id); + source_extension_id, target_extension_id); return true; } @@ -342,7 +352,8 @@ int ExtensionMessageService::OpenSpecialChannelToExtension( MSG_ROUTING_CONTROL); receiver.debug_info = 4; if (!OpenChannelOnUIThreadImpl( - source, NULL, receiver, port2_id, extension_id, channel_name)) + source, NULL, receiver, port2_id, extension_id, extension_id, + channel_name)) return -1; return port1_id; @@ -365,7 +376,7 @@ int ExtensionMessageService::OpenSpecialChannelToTab( receiver.debug_info = 5; if (!OpenChannelOnUIThreadImpl(source, NULL, receiver, port2_id, - extension_id, channel_name)) + extension_id, extension_id, channel_name)) return -1; return port1_id; diff --git a/chrome/browser/extensions/extension_message_service.h b/chrome/browser/extensions/extension_message_service.h index 10c579f..eb66bb6 100644 --- a/chrome/browser/extensions/extension_message_service.h +++ b/chrome/browser/extensions/extension_message_service.h @@ -114,7 +114,9 @@ class ExtensionMessageService // 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, + int OpenChannelToExtension(int routing_id, + const std::string& source_extension_id, + const std::string& target_extension_id, const std::string& channel_name, ResourceMessageFilter* source); @@ -146,7 +148,9 @@ class ExtensionMessageService // opened. void OpenChannelToExtensionOnUIThread( int source_process_id, int source_routing_id, int receiver_port_id, - const std::string& extension_id, const std::string& channel_name); + const std::string& source_extension_id, + const std::string& target_extension_id, + const std::string& channel_name); void OpenChannelToTabOnUIThread( int source_process_id, int source_routing_id, int receiver_port_id, @@ -157,7 +161,9 @@ class ExtensionMessageService bool OpenChannelOnUIThreadImpl( IPC::Message::Sender* source, TabContents* source_contents, const MessagePort& receiver, int receiver_port_id, - const std::string& extension_id, const std::string& channel_name); + const std::string& source_extension_id, + const std::string& target_extension_id, + const std::string& channel_name); // NotificationObserver interface. void Observe(NotificationType type, diff --git a/chrome/browser/extensions/extension_messages_apitest.cc b/chrome/browser/extensions/extension_messages_apitest.cc new file mode 100755 index 0000000..5b061af --- /dev/null +++ b/chrome/browser/extensions/extension_messages_apitest.cc @@ -0,0 +1,16 @@ +// Copyright (c) 2009 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/browser/extensions/extension_apitest.h" + +// Tests that message passing between extensions and content scripts works. +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MessagingExternal) { + ASSERT_TRUE(LoadExtension( + test_data_dir_.AppendASCII("..").AppendASCII("good") + .AppendASCII("Extensions") + .AppendASCII("bjafgdebaacbbbecmhlhpofkepfkgcpa") + .AppendASCII("1.0"))); + + ASSERT_TRUE(RunExtensionTest("connect_external")) << message_; +} diff --git a/chrome/browser/extensions/extension_messages_unittest.cc b/chrome/browser/extensions/extension_messages_unittest.cc index 8246097..cdb78cc 100644 --- a/chrome/browser/extensions/extension_messages_unittest.cc +++ b/chrome/browser/extensions/extension_messages_unittest.cc @@ -16,6 +16,7 @@ static void DispatchOnConnect(int source_port_id, const std::string& name, args.Set(1, Value::CreateStringValue(name)); args.Set(2, Value::CreateStringValue(tab_json)); args.Set(3, Value::CreateStringValue("")); // extension ID is empty for tests + args.Set(4, Value::CreateStringValue("")); // extension ID is empty for tests RendererExtensionBindings::Invoke( ExtensionMessageService::kDispatchOnConnect, args, NULL); } @@ -41,8 +42,7 @@ TEST_F(RenderViewTest, ExtensionMessagesOpenChannel) { render_thread_.sink().ClearMessages(); LoadHTML("<body></body>"); ExecuteJavaScript( - "var e = new chrome.Extension('foobar');" - "var port = e.connect({name:'testName'});" + "var port = chrome.extension.connect({name:'testName'});" "port.onMessage.addListener(doOnMessage);" "port.postMessage({message: 'content ready'});" "function doOnMessage(msg, port) {" @@ -57,7 +57,7 @@ TEST_F(RenderViewTest, ExtensionMessagesOpenChannel) { 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); + EXPECT_EQ("testName", open_params.d); const IPC::Message* post_msg = render_thread_.sink().GetUniqueMessageMatching( diff --git a/chrome/browser/renderer_host/resource_message_filter.cc b/chrome/browser/renderer_host/resource_message_filter.cc index c133d68..688179c 100644 --- a/chrome/browser/renderer_host/resource_message_filter.cc +++ b/chrome/browser/renderer_host/resource_message_filter.cc @@ -973,11 +973,13 @@ void ResourceMessageFilter::OnFreeTransportDIB( #endif void ResourceMessageFilter::OnOpenChannelToExtension( - int routing_id, const std::string& extension_id, + int routing_id, const std::string& source_extension_id, + const std::string& target_extension_id, const std::string& channel_name, int* port_id) { if (extensions_message_service_.get()) { *port_id = extensions_message_service_-> - OpenChannelToExtension(routing_id, extension_id, channel_name, this); + OpenChannelToExtension(routing_id, source_extension_id, + target_extension_id, channel_name, this); } else { *port_id = -1; } diff --git a/chrome/browser/renderer_host/resource_message_filter.h b/chrome/browser/renderer_host/resource_message_filter.h index a8a37af..b284d0d 100644 --- a/chrome/browser/renderer_host/resource_message_filter.h +++ b/chrome/browser/renderer_host/resource_message_filter.h @@ -251,7 +251,9 @@ 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, + void OnOpenChannelToExtension(int routing_id, + const std::string& source_extension_id, + const std::string& target_extension_id, const std::string& channel_name, int* port_id); void OnOpenChannelToTab(int routing_id, int tab_id, const std::string& extension_id, diff --git a/chrome/common/extensions/api/extension_api.json b/chrome/common/extensions/api/extension_api.json index 4ad7e46..5fe4d22 100755 --- a/chrome/common/extensions/api/extension_api.json +++ b/chrome/common/extensions/api/extension_api.json @@ -11,7 +11,15 @@ "onDisconnect": {"type": "object"}, "onMessage": {"type": "object"}, "postMessage": {"type": "function"}, - "tab": {"$ref": "Tab", "optional": true, "description":"This property will <b>only</b> be present on ports passed to onConnect listeners when the connection was opened from a tab or content script."} + "sender": { + "type": "object", + "optional": true, + "description": "This property will <b>only</b> be present on ports passed to onConnect/onConnectExternal listeners.", + "properties": { + "tab": {"$ref": "Tab", "optional": true, "description":"This property will <b>only</b> be present when the connection was opened from a tab or content script."}, + "id": {"type": "string", "description": "The extension ID of the extension that opened the connection."} + } + } } } ], @@ -31,6 +39,7 @@ "type": "function", "description": "Attempts to connect to other listeners within the extension (listeners may be toolstrips or the extension's background page). This is primarily useful for content scripts connecting to their extension processes. Extensions may connect to content scripts embedded in tabs via <a href='broken'><var>chrome.tabs.connectToTab</var></a>.", "parameters": [ + {"type": "string", "name": "extensionId", "optional": true, "description": "The extension ID of the extension you want to connect to. If omitted, default is your own extension."}, { "type": "object", "name": "connectInfo", @@ -116,6 +125,14 @@ "parameters": [ {"$ref": "Port", "name": "port"} ] + }, + { + "name": "onConnectExternal", + "type": "function", + "description": "Fired when a connection is made from another extension.", + "parameters": [ + {"$ref": "Port", "name": "port"} + ] } ] }, diff --git a/chrome/common/extensions/docs/extension.html b/chrome/common/extensions/docs/extension.html index 150f4dc..67acf9d 100755 --- a/chrome/common/extensions/docs/extension.html +++ b/chrome/common/extensions/docs/extension.html @@ -182,8 +182,10 @@ <li> <a href="#events">Events</a> <ol> - <li jsinstance="*0"> + <li jsinstance="0"> <a href="#event-onConnect">onConnect</a> + </li><li jsinstance="*1"> + <a href="#event-onConnectExternal">onConnectExternal</a> </li> </ol> </li> @@ -351,7 +353,8 @@ For details, see <div class="summary"><span>Port</span> <!-- Note: intentionally longer 80 columns --> - <span>chrome.extension.connect</span>(<span jsinstance="*0" class="optional"><span style="display: none; ">, </span><span>object</span> + <span>chrome.extension.connect</span>(<span jsinstance="0" class="optional"><span style="display: none; ">, </span><span>string</span> + <var><span>extensionId</span></var></span><span jsinstance="*1" class="optional"><span>, </span><span>object</span> <var><span>connectInfo</span></var></span>)</div> <div class="description"> @@ -361,7 +364,48 @@ For details, see <!-- PARAMETERS --> <h4>Parameters</h4> <dl> - <div jsinstance="*0"> + <div jsinstance="0"> + <div> + <dt> + <var>extensionId</var> + <em> + + <!-- TYPE --> + <div style="display:inline"> + ( + <span class="optional">optional</span> + <span id="typeTemplate"> + <span style="display: none; "> + <a> Type</a> + </span> + <span> + <span style="display: none; "> + array of <span><span></span></span> + </span> + <span>string</span> + </span> + </span> + ) + </div> + + </em> + </dt> + <dd class="todo" style="display: none; "> + Undocumented. + </dd> + <dd>The extension ID of the extension you want to connect to. If omitted, default is your own extension.</dd> + + <!-- OBJECT PROPERTIES --> + <dd style="display: none; "> + <dl> + <div> + <div> + </div> + </div> + </dl> + </dd> + </div> + </div><div jsinstance="*1"> <div> <dt> <var>connectInfo</var> @@ -1129,7 +1173,7 @@ For details, see <h3 id="events">Events</h3> <!-- iterates over all events --> - <div class="apiItem" jsinstance="*0"> + <div class="apiItem" jsinstance="0"> <a name="event-onConnect"></a> <h4>onConnect</h4> @@ -1193,6 +1237,70 @@ For details, see </div> <!-- /decription --> + </div><div class="apiItem" jsinstance="*1"> + <a name="event-onConnectExternal"></a> + <h4>onConnectExternal</h4> + + <div class="summary"> + <!-- Note: intentionally longer 80 columns --> + <span class="subdued">chrome.extension.</span><span>onConnectExternal</span><span class="subdued">.addListener</span>(function(<span>Port port</span>) <span class="subdued">{...}</span>); + </div> + + <div class="description"> + <p class="todo" style="display: none; ">Undocumented.</p> + <p>Fired when a connection is made from another extension.</p> + + <!-- PARAMETERS --> + <h4>Parameters</h4> + <dl> + <div jsinstance="*0"> + <div> + <dt> + <var>port</var> + <em> + + <!-- TYPE --> + <div style="display:inline"> + ( + <span class="optional" style="display: none; ">optional</span> + <span id="typeTemplate"> + <span> + <a href="extension.html#type-Port">Port</a> + </span> + <span style="display: none; "> + <span> + array of <span><span></span></span> + </span> + <span>paramType</span> + </span> + </span> + ) + </div> + + </em> + </dt> + <dd class="todo"> + Undocumented. + </dd> + <dd style="display: none; "> + Description of this parameter from the json schema. + </dd> + + <!-- OBJECT PROPERTIES --> + <dd style="display: none; "> + <dl> + <div> + <div> + </div> + </div> + </dl> + </dd> + </div> + </div> + </dl> + + </div> <!-- /decription --> + </div> <!-- /apiItem --> </div> <!-- /apiGroup --> @@ -1415,6 +1523,40 @@ For details, see </div><div jsinstance="*4"> <div> <dt> + <var>sender</var> + <em> + + <!-- TYPE --> + <div style="display:inline"> + ( + <span class="optional">optional</span> + <span id="typeTemplate"> + <span style="display: none; "> + <a> Type</a> + </span> + <span> + <span style="display: none; "> + array of <span><span></span></span> + </span> + <span>object</span> + </span> + </span> + ) + </div> + + </em> + </dt> + <dd class="todo" style="display: none; "> + Undocumented. + </dd> + <dd>This property will <b>only</b> be present on ports passed to onConnect/onConnectExternal listeners.</dd> + + <!-- OBJECT PROPERTIES --> + <dd> + <dl> + <div jsinstance="0"> + <div> + <dt> <var>tab</var> <em> @@ -1441,7 +1583,48 @@ For details, see <dd class="todo" style="display: none; "> Undocumented. </dd> - <dd>This property will <b>only</b> be present on ports passed to onConnect listeners when the connection was opened from a tab or content script.</dd> + <dd>This property will <b>only</b> be present when the connection was opened from a tab or content script.</dd> + + <!-- OBJECT PROPERTIES --> + <dd style="display: none; "> + <dl> + <div> + <div> + </div> + </div> + </dl> + </dd> + </div> + </div><div jsinstance="*1"> + <div> + <dt> + <var>id</var> + <em> + + <!-- TYPE --> + <div style="display:inline"> + ( + <span class="optional" style="display: none; ">optional</span> + <span id="typeTemplate"> + <span style="display: none; "> + <a> Type</a> + </span> + <span> + <span style="display: none; "> + array of <span><span></span></span> + </span> + <span>string</span> + </span> + </span> + ) + </div> + + </em> + </dt> + <dd class="todo" style="display: none; "> + Undocumented. + </dd> + <dd>The extension ID of the extension that opened the connection.</dd> <!-- OBJECT PROPERTIES --> <dd style="display: none; "> @@ -1457,6 +1640,10 @@ For details, see </dl> </dd> </div> + </div> + </dl> + </dd> + </div> </div> <!-- /apiItem --> diff --git a/chrome/common/render_messages_internal.h b/chrome/common/render_messages_internal.h index 5884888..7fff1dd 100644 --- a/chrome/common/render_messages_internal.h +++ b/chrome/common/render_messages_internal.h @@ -1723,9 +1723,10 @@ IPC_BEGIN_MESSAGES(ViewHost) // 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, + IPC_SYNC_MESSAGE_CONTROL4_1(ViewHostMsg_OpenChannelToExtension, int /* routing_id */, - std::string /* extension_id */, + std::string /* source_extension_id */, + std::string /* target_extension_id */, std::string /* channel_name */, int /* port_id */) diff --git a/chrome/renderer/extensions/bindings_utils.h b/chrome/renderer/extensions/bindings_utils.h index b0b3f08..471023c 100644 --- a/chrome/renderer/extensions/bindings_utils.h +++ b/chrome/renderer/extensions/bindings_utils.h @@ -28,6 +28,11 @@ class ExtensionBase : public v8::Extension { const char** deps) : v8::Extension(name, source, dep_count, deps) {} + // Note: do not call this function before or during the chromeHidden.onLoad + // event dispatch. The URL might not have been committed yet and might not + // be an extension URL. + static std::string ExtensionIdForCurrentContext(); + // Derived classes should call this at the end of their implementation in // order to expose common native functions, like GetChromeHidden, to the // v8 extension. diff --git a/chrome/renderer/extensions/renderer_extension_bindings.cc b/chrome/renderer/extensions/renderer_extension_bindings.cc index 374e673..de958d1 100644 --- a/chrome/renderer/extensions/renderer_extension_bindings.cc +++ b/chrome/renderer/extensions/renderer_extension_bindings.cc @@ -77,12 +77,15 @@ class ExtensionImpl : public ExtensionBase { if (!renderview) return v8::Undefined(); - 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()); + if (args.Length() >= 3 && args[0]->IsString() && args[1]->IsString() && + args[2]->IsString()) { + std::string source_id = *v8::String::Utf8Value(args[0]->ToString()); + std::string target_id = *v8::String::Utf8Value(args[1]->ToString()); + std::string channel_name = *v8::String::Utf8Value(args[2]->ToString()); int port_id = -1; renderview->Send(new ViewHostMsg_OpenChannelToExtension( - renderview->routing_id(), id, channel_name, &port_id)); + renderview->routing_id(), source_id, target_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 e99c618..6445dce 100644 --- a/chrome/renderer/mock_render_thread.cc +++ b/chrome/renderer/mock_render_thread.cc @@ -97,7 +97,8 @@ void MockRenderThread::OnMsgCreateWidget(int opener_id, } void MockRenderThread::OnMsgOpenChannelToExtension( - int routing_id, const std::string& extension_id, + int routing_id, const std::string& source_extension_id, + const std::string& target_extension_id, const std::string& channel_name, int* port_id) { *port_id = 0; } diff --git a/chrome/renderer/mock_render_thread.h b/chrome/renderer/mock_render_thread.h index 69a5186..eb1a458 100644 --- a/chrome/renderer/mock_render_thread.h +++ b/chrome/renderer/mock_render_thread.h @@ -84,7 +84,8 @@ class MockRenderThread : public RenderThreadBase { // The callee expects to be returned a valid channel_id. void OnMsgOpenChannelToExtension( int routing_id, const std::string& extension_id, - const std::string& channel_name, int* port_id); + const std::string& source_extension_id, + const std::string& target_extension_id, int* port_id); void OnDuplicateSection(base::SharedMemoryHandle renderer_handle, base::SharedMemoryHandle* browser_handle); diff --git a/chrome/renderer/resources/event_bindings.js b/chrome/renderer/resources/event_bindings.js index 3def161..dc69268 100644 --- a/chrome/renderer/resources/event_bindings.js +++ b/chrome/renderer/resources/event_bindings.js @@ -2,11 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// ----------------------------------------------------------------------------- -// NOTE: If you change this file you need to touch renderer_resources.grd to -// have your change take effect. -// ----------------------------------------------------------------------------- - var chrome = chrome || {}; (function () { native function GetChromeHidden(); @@ -105,6 +100,11 @@ var chrome = chrome || {}; return this.findListeners_(cb) > -1; }; + // Test if any callbacks are registered for this event. + chrome.Event.prototype.hasListeners = function(cb) { + return this.listeners_.length > 0; + }; + // Returns the index of the given callback if registered, or -1 if not // found. chrome.Event.prototype.findListener_ = function(cb) { diff --git a/chrome/renderer/resources/extension_process_bindings.js b/chrome/renderer/resources/extension_process_bindings.js index 6dfa25a..0ac0be4 100644 --- a/chrome/renderer/resources/extension_process_bindings.js +++ b/chrome/renderer/resources/extension_process_bindings.js @@ -2,11 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// ----------------------------------------------------------------------------- -// NOTE: If you change this file you need to touch renderer_resources.grd to -// 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. @@ -221,11 +216,7 @@ var chrome = chrome || {}; } chromeHidden.onLoad.addListener(function (extensionId) { - chrome.extension = new chrome.Extension(extensionId); - - // TODO(mpcomplete): chrome.self is deprecated. Remove it at 1.0. - // http://code.google.com/p/chromium/issues/detail?id=16356 - chrome.self = chrome.extension; + chrome.initExtension(extensionId); // |apiFunctions| is a hash of name -> object that stores the // name & definition of the apiFunction. Custom handling of api functions @@ -297,7 +288,7 @@ var chrome = chrome || {}; name = connectInfo.name || name; } var portId = OpenChannelToTab( - tabId, chrome.extension.id_, name); + tabId, chromeHidden.extensionId, name); return chromeHidden.Port.createPort(portId, name); } diff --git a/chrome/renderer/resources/renderer_extension_bindings.js b/chrome/renderer/resources/renderer_extension_bindings.js index 6e9b387..09021540 100644 --- a/chrome/renderer/resources/renderer_extension_bindings.js +++ b/chrome/renderer/resources/renderer_extension_bindings.js @@ -2,11 +2,6 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -// ----------------------------------------------------------------------------- -// NOTE: If you change this file you need to touch renderer_resources.grd to -// 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. @@ -16,7 +11,7 @@ var chrome = chrome || {}; (function () { - native function OpenChannelToExtension(id, name); + native function OpenChannelToExtension(sourceId, targetId, name); native function CloseChannel(portId); native function PortAddRef(portId); native function PortRelease(portId); @@ -56,19 +51,28 @@ var chrome = chrome || {}; // Called by native code when a channel has been opened to this context. chromeHidden.Port.dispatchOnConnect = function(portId, channelName, tab, - extensionId) { + sourceExtensionId, + targetExtensionId) { // 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)) { + if (targetExtensionId != chromeHidden.extensionId) + return; // not for us + + // Determine whether this is coming from another extension, and use the + // right event. + var connectEvent = (sourceExtensionId == chromeHidden.extensionId ? + chrome.extension.onConnect : chrome.extension.onConnectExternal); + if (connectEvent.hasListeners()) { var port = chromeHidden.Port.createPort(portId, channelName); if (tab) { tab = JSON.parse(tab); } - port.tab = tab; - chromeHidden.Event.dispatch(connectEvent, [port]); + port.sender = {tab: tab, id: sourceExtensionId}; + // TODO(EXTENSIONS_DEPRECATED): port.tab is obsolete. + port.tab = port.sender.tab; + connectEvent.dispatch(port); } }; @@ -107,30 +111,43 @@ var chrome = chrome || {}; CloseChannel(this.portId_); } - // Extension object. - chrome.Extension = function(id) { - this.id_ = id; - this.onConnect = new chrome.Event('channel-connect:' + id); - }; - - // Opens a message channel to the extension. Returns a Port for - // message passing. - chrome.Extension.prototype.connect = function(connectInfo) { - var name = ""; - if (connectInfo) { - name = connectInfo.name || name; - } - var portId = OpenChannelToExtension(this.id_, name); - if (portId == -1) - throw new Error("No such extension: '" + this.id_ + "'"); - return chromeHidden.Port.createPort(portId, name); - }; - - // Returns a resource URL that can be used to fetch a resource from this - // extension. - chrome.Extension.prototype.getURL = function(path) { - return "chrome-extension://" + this.id_ + "/" + path; - }; - - chrome.self = chrome.self || {}; + // This function is called on context initialization for both content scripts + // and extension contexts. + chrome.initExtension = function(extensionId) { + delete chrome.initExtension; + chromeHidden.extensionId = extensionId; + + chrome.extension = chrome.extension || {}; + + // TODO(EXTENSIONS_DEPRECATED): chrome.self is obsolete. + // http://code.google.com/p/chromium/issues/detail?id=16356 + chrome.self = chrome.extension; + + // Events for when a message channel is opened to our extension. + chrome.extension.onConnect = new chrome.Event(); + chrome.extension.onConnectExternal = new chrome.Event(); + + // Opens a message channel to the given target extension, or the current one + // if unspecified. Returns a Port for message passing. + chrome.extension.connect = function(targetId_opt, connectInfo_opt) { + var name = ""; + var targetId = extensionId; + var nextArg = 0; + if (typeof(arguments[nextArg]) == "string") + targetId = arguments[nextArg++]; + if (typeof(arguments[nextArg]) == "object") + name = arguments[nextArg++].name || name; + + var portId = OpenChannelToExtension(extensionId, targetId, name); + if (portId >= 0) + return chromeHidden.Port.createPort(portId, name); + throw new Error("Error connecting to extension '" + targetId + "'"); + }; + + // Returns a resource URL that can be used to fetch a resource from this + // extension. + chrome.extension.getURL = function(path) { + return "chrome-extension://" + extensionId + "/" + path; + }; + } })(); diff --git a/chrome/renderer/user_script_slave.cc b/chrome/renderer/user_script_slave.cc index 86fcc1a..f3df33c 100644 --- a/chrome/renderer/user_script_slave.cc +++ b/chrome/renderer/user_script_slave.cc @@ -25,12 +25,8 @@ using WebKit::WebString; static const char kUserScriptHead[] = "(function (unsafeWindow) {\n"; static const char kUserScriptTail[] = "\n})(window);"; -// Creates a convenient reference to a content script's parent extension. -// TODO(mpcomplete): self.onConnect is deprecated. Remove it at 1.0. -// http://code.google.com/p/chromium/issues/detail?id=16356 -static const char kInitExtension[] = - "chrome.extension = new chrome.Extension('%s');" - "chrome.self.onConnect = chrome.extension.onConnect;"; +// Sets up the chrome.extension module. +static const char kInitExtension[] = "chrome.initExtension('%s');"; int UserScriptSlave::GetIsolatedWorldId(const std::string& extension_id) { typedef std::map<std::string, int> IsolatedWorldMap; diff --git a/chrome/test/data/extensions/api_test/connect_external/connect.html b/chrome/test/data/extensions/api_test/connect_external/connect.html new file mode 100644 index 0000000..cc9def8 --- /dev/null +++ b/chrome/test/data/extensions/api_test/connect_external/connect.html @@ -0,0 +1,13 @@ +<script> +var testId = "bjafgdebaacbbbecmhlhpofkepfkgcpa"; + +function testConnectExternal() { + var port = chrome.extension.connect(testId, {name: "extern"}); + port.postMessage({testConnectExternal: true}); + port.onMessage.addListener(function(msg) { + var success = msg.success && msg.senderId == location.host; + window.domAutomationController.send(success); + port.disconnect(); + }); +} +</script> diff --git a/chrome/test/data/extensions/api_test/connect_external/manifest.json b/chrome/test/data/extensions/api_test/connect_external/manifest.json new file mode 100644 index 0000000..c1b30cb --- /dev/null +++ b/chrome/test/data/extensions/api_test/connect_external/manifest.json @@ -0,0 +1,6 @@ +{ + "name": "connect_external", + "version": "1.0", + "description": "Tests connect to an external extension.", + "background_page": "test.html" +} diff --git a/chrome/test/data/extensions/good/Extensions/bjafgdebaacbbbecmhlhpofkepfkgcpa/1.0/toolstrip.html b/chrome/test/data/extensions/good/Extensions/bjafgdebaacbbbecmhlhpofkepfkgcpa/1.0/toolstrip.html index 84c7db0..fb4c2eb 100644 --- a/chrome/test/data/extensions/good/Extensions/bjafgdebaacbbbecmhlhpofkepfkgcpa/1.0/toolstrip.html +++ b/chrome/test/data/extensions/good/Extensions/bjafgdebaacbbbecmhlhpofkepfkgcpa/1.0/toolstrip.html @@ -11,6 +11,13 @@ window.onload = function() { // Ignore other messages since they are from us. }); }); + chrome.extension.onConnectExternal.addListener(function(port) { + port.onMessage.addListener(function(msg) { + if (msg.testConnectExternal) { + port.postMessage({success: true, senderId: port.sender.id}); + } + }); + }); }; // Tests that postMessage to the tab and its response works. |