diff options
-rw-r--r-- | chrome/browser/extensions/extension_messages_apitest.cc | 6 | ||||
-rwxr-xr-x | chrome/chrome.gyp | 2 | ||||
-rwxr-xr-x | chrome/common/extensions/api/extension_api.json | 55 | ||||
-rw-r--r-- | chrome/common/extensions/docs/extension.html | 403 | ||||
-rw-r--r-- | chrome/common/extensions/docs/tabs.html | 189 | ||||
-rw-r--r-- | chrome/renderer/resources/extension_process_bindings.js | 12 | ||||
-rw-r--r-- | chrome/renderer/resources/renderer_extension_bindings.js | 58 | ||||
-rw-r--r-- | chrome/test/data/extensions/api_test/connect/manifest.json | 13 | ||||
-rw-r--r-- | chrome/test/data/extensions/api_test/connect/page.js | 10 | ||||
-rw-r--r-- | chrome/test/data/extensions/api_test/connect/test.html | 33 | ||||
-rw-r--r-- | chrome/test/data/extensions/api_test/connect_external/connect.html | 13 | ||||
-rw-r--r-- | chrome/test/data/extensions/api_test/connect_external/test.html | 15 |
12 files changed, 784 insertions, 25 deletions
diff --git a/chrome/browser/extensions/extension_messages_apitest.cc b/chrome/browser/extensions/extension_messages_apitest.cc index 5b061af..c4e58cb 100644 --- a/chrome/browser/extensions/extension_messages_apitest.cc +++ b/chrome/browser/extensions/extension_messages_apitest.cc @@ -5,6 +5,12 @@ #include "chrome/browser/extensions/extension_apitest.h" // Tests that message passing between extensions and content scripts works. +IN_PROC_BROWSER_TEST_F(ExtensionApiTest, Messaging) { + StartHTTPServer(); + ASSERT_TRUE(RunExtensionTest("connect")) << message_; +} + +// Tests that message passing from one extension to another works. IN_PROC_BROWSER_TEST_F(ExtensionApiTest, MessagingExternal) { ASSERT_TRUE(LoadExtension( test_data_dir_.AppendASCII("..").AppendASCII("good") diff --git a/chrome/chrome.gyp b/chrome/chrome.gyp index 43ea689..98ce90b 100755 --- a/chrome/chrome.gyp +++ b/chrome/chrome.gyp @@ -66,6 +66,7 @@ 'browser/extensions/extension_apitest.h', 'browser/extensions/extension_bookmarks_apitest.cc', 'browser/extensions/extension_javascript_url_apitest.cc', + 'browser/extensions/extension_messages_apitest.cc', 'browser/extensions/extension_browsertest.cc', 'browser/extensions/extension_browsertest.h', 'browser/extensions/extension_browsertests_misc.cc', @@ -105,6 +106,7 @@ 'browser/extensions/extension_apitest.h', 'browser/extensions/extension_bookmarks_apitest.cc', 'browser/extensions/extension_javascript_url_apitest.cc', + 'browser/extensions/extension_messages_apitest.cc', 'browser/extensions/extension_browsertest.cc', 'browser/extensions/extension_browsertest.h', 'browser/extensions/extension_browsertests_misc.cc', diff --git a/chrome/common/extensions/api/extension_api.json b/chrome/common/extensions/api/extension_api.json index e629088..ab44b7d 100755 --- a/chrome/common/extensions/api/extension_api.json +++ b/chrome/common/extensions/api/extension_api.json @@ -55,6 +55,20 @@ } }, { + "name": "sendRequest", + "type": "function", + "description": "Sends a single request to other listeners within the extension. Similar to chrome.extension.connect, but only sends a single request with an optional response.", + "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": "any", "name": "request" }, + { + "type": "function", + "name": "responseCallback", + "optional": true + } + ] + }, + { "name": "getURL", "type": "function", "description": "Convert a relative path within an extension install directory to a fully-qualified URL.", @@ -133,6 +147,24 @@ "parameters": [ {"$ref": "Port", "name": "port"} ] + }, + { + "name": "onRequest", + "type": "function", + "description": "Fired when a request is sent from either an extension process or a content script.", + "parameters": [ + { "type": "any", "name": "request" }, + { "type": "function", "name": "sendResponse", "description": "Function to call when you have a response. The argument should be any JSON-ifiable object, or undefined if there is no response." } + ] + }, + { + "name": "onRequestExternal", + "type": "function", + "description": "Fired when a request is sent from another extension.", + "parameters": [ + { "type": "any", "name": "request" }, + { "type": "function", "name": "sendResponse", "description": "Function to call when you have a response. The argument should be any JSON-ifiable object, or undefined if there is no response." } + ] } ] }, @@ -367,7 +399,7 @@ { "name": "connect", "type": "function", - "description": "Connects to the content script(s) in the specified tab. The <a href='extension.html#event-onConnect'>chrome.extensions.onConnect</a> event is fired in each content script running in the specified tab for the current extension. For more details, see <a href='content_scripts.html#messaging'>Content Script Messaging</a>.", + "description": "Connects to the content script(s) in the specified tab. The <a href='extension.html#event-onConnect'>chrome.extension.onConnect</a> event is fired in each content script running in the specified tab for the current extension. For more details, see <a href='content_scripts.html#messaging'>Content Script Messaging</a>.", "parameters": [ { "type": "integer", @@ -389,6 +421,27 @@ } }, { + "name": "sendRequest", + "type": "function", + "description": "Sends a single request to the content script(s) in the specified tab, with an optional callback to run when a response is sent back. The <a href='extension.html#event-onRequest'>chrome.extension.onRequest</a> event is fired in each content script running in the specified tab for the current extension.", + "parameters": [ + { + "type": "integer", + "name": "tabId", + "minimum": 0 + }, + { + "type": "any", + "name": "request" + }, + { + "type": "function", + "name": "responseCallback", + "optional": true + } + ] + }, + { "name": "getSelected", "type": "function", "description": "Gets the tab that is selected in the specified window.", diff --git a/chrome/common/extensions/docs/extension.html b/chrome/common/extensions/docs/extension.html index 514c710..af22583 100644 --- a/chrome/common/extensions/docs/extension.html +++ b/chrome/common/extensions/docs/extension.html @@ -193,8 +193,10 @@ <a href="#method-getToolstrips">getToolstrips</a> </li><li jsinstance="4"> <a href="#method-getURL">getURL</a> - </li><li jsinstance="*5"> + </li><li jsinstance="5"> <a href="#method-getViews">getViews</a> + </li><li jsinstance="*6"> + <a href="#method-sendRequest">sendRequest</a> </li> </ol> </li> @@ -203,8 +205,12 @@ <ol> <li jsinstance="0"> <a href="#event-onConnect">onConnect</a> - </li><li jsinstance="*1"> + </li><li jsinstance="1"> <a href="#event-onConnectExternal">onConnectExternal</a> + </li><li jsinstance="2"> + <a href="#event-onRequest">onRequest</a> + </li><li jsinstance="*3"> + <a href="#event-onRequestExternal">onRequestExternal</a> </li> </ol> </li> @@ -1081,7 +1087,7 @@ For details, see </div> <!-- /description --> - </div><div class="apiItem" jsinstance="*5"> + </div><div class="apiItem" jsinstance="5"> <a name="method-getViews"></a> <!-- method-anchor --> <h4>getViews</h4> @@ -1182,6 +1188,185 @@ For details, see </div> <!-- /description --> + </div><div class="apiItem" jsinstance="*6"> + <a name="method-sendRequest"></a> <!-- method-anchor --> + <h4>sendRequest</h4> + + <div class="summary"><span style="display: none; ">void</span> + <!-- Note: intentionally longer 80 columns --> + <span>chrome.extension.sendRequest</span>(<span jsinstance="0" class="optional"><span style="display: none; ">, </span><span>string</span> + <var><span>extensionId</span></var></span><span jsinstance="1" class="null"><span>, </span><span>any</span> + <var><span>request</span></var></span><span jsinstance="*2" class="optional"><span>, </span><span>function</span> + <var><span>responseCallback</span></var></span>)</div> + + <div class="description"> + <p class="todo" style="display: none; ">Undocumented.</p> + <p>Sends a single request to other listeners within the extension. Similar to chrome.extension.connect, but only sends a single request with an optional response.</p> + + <!-- PARAMETERS --> + <h4>Parameters</h4> + <dl> + <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>request</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>any</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><div jsinstance="*2"> + <div> + <dt> + <var>responseCallback</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>function</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> + + <!-- RETURNS --> + <h4 style="display: none; ">Returns</h4> + <dl> + <div style="display: none; "> + <div> + </div> + </div> + </dl> + + <!-- CALLBACK --> + <div> + <div> + <h4>Callback function</h4> + <p> + If you specify the <em>callback</em> parameter, + it should specify a function that looks like this: + </p> + + <!-- Note: intentionally longer 80 columns --> + <pre>function(<span>null</span>) <span class="subdued">{...}</span>);</pre> + <dl> + <div style="display: none; "> + <div> + </div> + </div> + </dl> + </div> + </div> + + </div> <!-- /description --> + </div> <!-- /apiItem --> </div> <!-- /apiGroup --> @@ -1256,7 +1441,7 @@ For details, see </div> <!-- /decription --> - </div><div class="apiItem" jsinstance="*1"> + </div><div class="apiItem" jsinstance="1"> <a name="event-onConnectExternal"></a> <h4>onConnectExternal</h4> @@ -1320,6 +1505,216 @@ For details, see </div> <!-- /decription --> + </div><div class="apiItem" jsinstance="2"> + <a name="event-onRequest"></a> + <h4>onRequest</h4> + + <div class="summary"> + <!-- Note: intentionally longer 80 columns --> + <span class="subdued">chrome.extension.</span><span>onRequest</span><span class="subdued">.addListener</span>(function(<span>any request, function sendResponse</span>) <span class="subdued">{...}</span>); + </div> + + <div class="description"> + <p class="todo" style="display: none; ">Undocumented.</p> + <p>Fired when a request is sent from either an extension process or a content script.</p> + + <!-- PARAMETERS --> + <h4>Parameters</h4> + <dl> + <div jsinstance="0"> + <div> + <dt> + <var>request</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>any</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><div jsinstance="*1"> + <div> + <dt> + <var>sendResponse</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>function</span> + </span> + </span> + ) + </div> + + </em> + </dt> + <dd class="todo" style="display: none; "> + Undocumented. + </dd> + <dd>Function to call when you have a response. The argument should be any JSON-ifiable object, or undefined if there is no response.</dd> + + <!-- OBJECT PROPERTIES --> + <dd style="display: none; "> + <dl> + <div> + <div> + </div> + </div> + </dl> + </dd> + </div> + </div> + </dl> + + </div> <!-- /decription --> + + </div><div class="apiItem" jsinstance="*3"> + <a name="event-onRequestExternal"></a> + <h4>onRequestExternal</h4> + + <div class="summary"> + <!-- Note: intentionally longer 80 columns --> + <span class="subdued">chrome.extension.</span><span>onRequestExternal</span><span class="subdued">.addListener</span>(function(<span>any request, function sendResponse</span>) <span class="subdued">{...}</span>); + </div> + + <div class="description"> + <p class="todo" style="display: none; ">Undocumented.</p> + <p>Fired when a request is sent from another extension.</p> + + <!-- PARAMETERS --> + <h4>Parameters</h4> + <dl> + <div jsinstance="0"> + <div> + <dt> + <var>request</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>any</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><div jsinstance="*1"> + <div> + <dt> + <var>sendResponse</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>function</span> + </span> + </span> + ) + </div> + + </em> + </dt> + <dd class="todo" style="display: none; "> + Undocumented. + </dd> + <dd>Function to call when you have a response. The argument should be any JSON-ifiable object, or undefined if there is no response.</dd> + + <!-- OBJECT PROPERTIES --> + <dd style="display: none; "> + <dl> + <div> + <div> + </div> + </div> + </dl> + </dd> + </div> + </div> + </dl> + + </div> <!-- /decription --> + </div> <!-- /apiItem --> </div> <!-- /apiGroup --> diff --git a/chrome/common/extensions/docs/tabs.html b/chrome/common/extensions/docs/tabs.html index eb765ae..12dbdb9 100644 --- a/chrome/common/extensions/docs/tabs.html +++ b/chrome/common/extensions/docs/tabs.html @@ -205,7 +205,9 @@ <a href="#method-move">move</a> </li><li jsinstance="10"> <a href="#method-remove">remove</a> - </li><li jsinstance="*11"> + </li><li jsinstance="11"> + <a href="#method-sendRequest">sendRequest</a> + </li><li jsinstance="*12"> <a href="#method-update">update</a> </li> </ol> @@ -485,7 +487,7 @@ For example: <div class="description"> <p class="todo" style="display: none; ">Undocumented.</p> - <p>Connects to the content script(s) in the specified tab. The <a href="extension.html#event-onConnect">chrome.extensions.onConnect</a> event is fired in each content script running in the specified tab for the current extension. For more details, see <a href="content_scripts.html#messaging">Content Script Messaging</a>.</p> + <p>Connects to the content script(s) in the specified tab. The <a href="extension.html#event-onConnect">chrome.extension.onConnect</a> event is fired in each content script running in the specified tab for the current extension. For more details, see <a href="content_scripts.html#messaging">Content Script Messaging</a>.</p> <!-- PARAMETERS --> <h4>Parameters</h4> @@ -2755,7 +2757,188 @@ For example: </div> <!-- /description --> - </div><div class="apiItem" jsinstance="*11"> + </div><div class="apiItem" jsinstance="11"> + <a name="method-sendRequest"></a> <!-- method-anchor --> + <h4>sendRequest</h4> + + <div class="summary"><span style="display: none; ">void</span> + <!-- Note: intentionally longer 80 columns --> + <span>chrome.tabs.sendRequest</span>(<span jsinstance="0" class="null"><span style="display: none; ">, </span><span>integer</span> + <var><span>tabId</span></var></span><span jsinstance="1" class="null"><span>, </span><span>any</span> + <var><span>request</span></var></span><span jsinstance="*2" class="optional"><span>, </span><span>function</span> + <var><span>responseCallback</span></var></span>)</div> + + <div class="description"> + <p class="todo" style="display: none; ">Undocumented.</p> + <p>Sends a single request to the content script(s) in the specified tab, with an optional callback to run when a response is sent back. The <a href="extension.html#event-onRequest">chrome.extension.onRequest</a> event is fired in each content script running in the specified tab for the current extension.</p> + + <!-- PARAMETERS --> + <h4>Parameters</h4> + <dl> + <div jsinstance="0"> + <div> + <dt> + <var>tabId</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>integer</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><div jsinstance="1"> + <div> + <dt> + <var>request</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>any</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><div jsinstance="*2"> + <div> + <dt> + <var>responseCallback</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>function</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> + + <!-- RETURNS --> + <h4 style="display: none; ">Returns</h4> + <dl> + <div style="display: none; "> + <div> + </div> + </div> + </dl> + + <!-- CALLBACK --> + <div> + <div> + <h4>Callback function</h4> + <p> + If you specify the <em>callback</em> parameter, + it should specify a function that looks like this: + </p> + + <!-- Note: intentionally longer 80 columns --> + <pre>function(<span>null</span>) <span class="subdued">{...}</span>);</pre> + <dl> + <div style="display: none; "> + <div> + </div> + </div> + </dl> + </div> + </div> + + </div> <!-- /description --> + + </div><div class="apiItem" jsinstance="*12"> <a name="method-update"></a> <!-- method-anchor --> <h4>update</h4> diff --git a/chrome/renderer/resources/extension_process_bindings.js b/chrome/renderer/resources/extension_process_bindings.js index ab5fee3..3974867 100644 --- a/chrome/renderer/resources/extension_process_bindings.js +++ b/chrome/renderer/resources/extension_process_bindings.js @@ -294,6 +294,18 @@ var chrome = chrome || {}; return chromeHidden.Port.createPort(portId, name); } + apiFunctions["tabs.sendRequest"].handleRequest = + function(tabId, request, responseCallback) { + var port = chrome.tabs.connect(tabId, + {name: chromeHidden.kRequestChannel}); + port.postMessage(request); + port.onMessage.addListener(function(response) { + if (responseCallback) + responseCallback(response); + port.disconnect(); + }); + } + apiFunctions["extension.getViews"].handleRequest = function() { return GetExtensionViews(-1, "ALL"); } diff --git a/chrome/renderer/resources/renderer_extension_bindings.js b/chrome/renderer/resources/renderer_extension_bindings.js index 09021540..bf288bd 100644 --- a/chrome/renderer/resources/renderer_extension_bindings.js +++ b/chrome/renderer/resources/renderer_extension_bindings.js @@ -20,9 +20,16 @@ var chrome = chrome || {}; var chromeHidden = GetChromeHidden(); + // The reserved channel name for the sendRequest API. + chromeHidden.kRequestChannel = "chrome.extension.sendRequest"; + // Map of port IDs to port object. var ports = {}; + // Change even to odd and vice versa, to get the other side of a given + // channel. + function getOppositePortId(portId) { return portId ^ 1; } + // Port object. Represents a connection to another script context through // which messages can be passed. chrome.Port = function(portId, opt_name) { @@ -59,11 +66,30 @@ var chrome = chrome || {}; // close both. if (targetExtensionId != chromeHidden.extensionId) return; // not for us + if (ports[getOppositePortId(portId)]) + return; // this channel was opened by us, so ignore it + + // Determine whether this is coming from another extension, so we can use + // the right event. + var isExternal = sourceExtensionId != chromeHidden.extensionId; + + // Special case for sendRequest/onRequest. + if (channelName == chromeHidden.kRequestChannel) { + var requestEvent = (isExternal ? + chrome.extension.onRequestExternal : chrome.extension.onRequest); + if (requestEvent.hasListeners()) { + var port = chromeHidden.Port.createPort(portId, channelName); + port.onMessage.addListener(function(request) { + requestEvent.dispatch(request, function(response) { + port.postMessage(response); + }); + }); + } + return; + } - // Determine whether this is coming from another extension, and use the - // right event. - var connectEvent = (sourceExtensionId == chromeHidden.extensionId ? - chrome.extension.onConnect : chrome.extension.onConnectExternal); + var connectEvent = (isExternal ? + chrome.extension.onConnectExternal : chrome.extension.onConnect); if (connectEvent.hasListeners()) { var port = chromeHidden.Port.createPort(portId, channelName); if (tab) { @@ -72,6 +98,7 @@ var chrome = chrome || {}; port.sender = {tab: tab, id: sourceExtensionId}; // TODO(EXTENSIONS_DEPRECATED): port.tab is obsolete. port.tab = port.sender.tab; + connectEvent.dispatch(port); } }; @@ -126,6 +153,8 @@ var chrome = chrome || {}; // Events for when a message channel is opened to our extension. chrome.extension.onConnect = new chrome.Event(); chrome.extension.onConnectExternal = new chrome.Event(); + chrome.extension.onRequest = new chrome.Event(); + chrome.extension.onRequestExternal = new chrome.Event(); // Opens a message channel to the given target extension, or the current one // if unspecified. Returns a Port for message passing. @@ -144,6 +173,27 @@ var chrome = chrome || {}; throw new Error("Error connecting to extension '" + targetId + "'"); }; + chrome.extension.sendRequest = + function(targetId_opt, request, responseCallback_opt) { + var targetId = extensionId; + var responseCallback = null; + var lastArg = arguments.length - 1; + if (typeof(arguments[lastArg]) == "function") + responseCallback = arguments[lastArg--]; + request = arguments[lastArg--]; + if (lastArg >= 0) + targetId = arguments[lastArg--]; + + var port = chrome.extension.connect(targetId, + {name: chromeHidden.kRequestChannel}); + port.postMessage(request); + port.onMessage.addListener(function(response) { + if (responseCallback) + responseCallback(response); + port.disconnect(); + }); + }; + // Returns a resource URL that can be used to fetch a resource from this // extension. chrome.extension.getURL = function(path) { diff --git a/chrome/test/data/extensions/api_test/connect/manifest.json b/chrome/test/data/extensions/api_test/connect/manifest.json new file mode 100644 index 0000000..27e16d3 --- /dev/null +++ b/chrome/test/data/extensions/api_test/connect/manifest.json @@ -0,0 +1,13 @@ +{ + "name": "connect_external", + "version": "1.0", + "description": "Tests connect from a content script.", + "permissions": ["tabs"], + "background_page": "test.html", + "content_scripts": [ + { + "matches": ["http://*/*"], + "js": ["page.js"] + } + ] +} diff --git a/chrome/test/data/extensions/api_test/connect/page.js b/chrome/test/data/extensions/api_test/connect/page.js new file mode 100644 index 0000000..d70f415 --- /dev/null +++ b/chrome/test/data/extensions/api_test/connect/page.js @@ -0,0 +1,10 @@ +// For test onRequest. +chrome.extension.sendRequest({step: 1}, function(response) { + if (response.nextStep) + chrome.extension.sendRequest({step: 2}); +}); + +// For test sendRequest. +chrome.extension.onRequest.addListener(function(request, sendResponse) { + sendResponse({success: (request.step2 == 1)}); +}); diff --git a/chrome/test/data/extensions/api_test/connect/test.html b/chrome/test/data/extensions/api_test/connect/test.html new file mode 100644 index 0000000..31868b4 --- /dev/null +++ b/chrome/test/data/extensions/api_test/connect/test.html @@ -0,0 +1,33 @@ +<script> +chrome.test.runTests([ + // Tests receiving a request from a content script and responding. + function onRequest() { + chrome.extension.onRequest.addListener(function(request, sendResponse) { + if (request.step == 1) { + // Step 1: Page should send another request for step 2. + sendResponse({nextStep: true}); + } else { + // Step 2. + chrome.test.assertEq(request.step, 2); + sendResponse({}); + chrome.test.succeed(); + } + }); + }, + // Tests sending a request to a tab and receiving a response. + function sendRequest() { + chrome.tabs.getSelected(null, function(tab) { + chrome.test.log('Selected tab: ' + tab.url); + chrome.tabs.sendRequest(tab.id, {step2: 1}, function(response) { + chrome.test.assertTrue(response.success); + chrome.test.succeed(); + }); + }); + } +]); + +chrome.test.log("Creating tab..."); +chrome.tabs.create({ + url: "http://localhost:1337/files/extensions/test_file.html" +}); +</script> diff --git a/chrome/test/data/extensions/api_test/connect_external/connect.html b/chrome/test/data/extensions/api_test/connect_external/connect.html deleted file mode 100644 index cc9def8..0000000 --- a/chrome/test/data/extensions/api_test/connect_external/connect.html +++ /dev/null @@ -1,13 +0,0 @@ -<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/test.html b/chrome/test/data/extensions/api_test/connect_external/test.html new file mode 100644 index 0000000..cc9cfa4 --- /dev/null +++ b/chrome/test/data/extensions/api_test/connect_external/test.html @@ -0,0 +1,15 @@ +<script> +var testId = "bjafgdebaacbbbecmhlhpofkepfkgcpa"; + +chrome.test.runTests([ + function connectExternal() { + var port = chrome.extension.connect(testId, {name: "extern"}); + port.postMessage({testConnectExternal: true}); + port.onMessage.addListener(chrome.test.callbackPass(function(msg) { + chrome.test.assertTrue(msg.success, "Message failed."); + chrome.test.assertEq(msg.senderId, location.host, + "Sender ID doesn't match."); + })); + } +]); +</script> |