Home | History | Annotate | Download | only in static
      1 <div id="pageData-name" class="pageData">Message Passing</div>
      2 <div id="pageData-showTOC" class="pageData">true</div>
      3 
      4 <p>
      5 Since content scripts run in the context of a web page and not the extension,
      6 they often need some way of communicating with the rest of the extension. For
      7 example, an RSS reader extension might use content scripts to detect the
      8 presence of an RSS feed on a page, then notify the background page in order to
      9 display a page action icon for that page.
     10 
     11 <p>
     12 Communication between extensions and their content scripts works by using
     13 message passing. Either side can listen for messages sent from the other end,
     14 and respond on the same channel. A message can contain any valid JSON object
     15 (null, boolean, number, string, array, or object). There is a simple API for
     16 <a href="#simple">one-time requests</a>
     17 and a more complex API that allows you to have
     18 <a href="#connect">long-lived connections</a>
     19 for exchanging multiple messages with a shared context. It is also possible to
     20 send a message to another extension if you know its ID, which is covered in
     21 the
     22 <a href="#external">cross-extension messages</a>
     23 section.
     24 
     25 
     26 <h2 id="simple">Simple one-time requests</h2>
     27 <p>
     28 If you only need to send a single message to another part of your extension
     29 (and optionally get a response back), you should use the simplified
     30 <a href="extension.html#method-sendRequest">chrome.extension.sendRequest()</a>
     31 or
     32 <a href="tabs.html#method-sendRequest">chrome.tabs.sendRequest()</a>
     33 methods. This lets you send a one-time JSON-serializable message from a
     34 content script to extension, or vice versa, respectively. An optional
     35 callback parameter allows you handle the response from the other side, if
     36 there is one.
     37 
     38 <p>
     39 Sending a request from a content script looks like this:
     40 <pre>
     41 contentscript.js
     42 ================
     43 chrome.extension.sendRequest({greeting: "hello"}, function(response) {
     44   console.log(response.farewell);
     45 });
     46 </pre>
     47 
     48 <p>
     49 Sending a request from the extension to a content script looks very similar,
     50 except that you need to specify which tab to send it to. This example
     51 demonstrates sending a message to the content script in the selected tab.
     52 <pre>
     53 background.html
     54 ===============
     55 chrome.tabs.getSelected(null, function(tab) {
     56   chrome.tabs.sendRequest(tab.id, {greeting: "hello"}, function(response) {
     57     console.log(response.farewell);
     58   });
     59 });
     60 </pre>
     61 
     62 <p>
     63 On the receiving end, you need to set up an
     64 <a href="extension.html#event-onRequest">chrome.extension.onRequest</a>
     65 event listener to handle the message. This looks the same from a content
     66 script or extension page. The request will remain open until you call
     67 sendResponse, so it is good practice to call sendResponse with an empty
     68 object to allow the request to be cleaned up.
     69 <pre>
     70 chrome.extension.onRequest.addListener(
     71   function(request, sender, sendResponse) {
     72     console.log(sender.tab ?
     73                 "from a content script:" + sender.tab.url :
     74                 "from the extension");
     75     if (request.greeting == "hello")
     76       sendResponse({farewell: "goodbye"});
     77     else
     78       sendResponse({}); // snub them.
     79   });
     80 </pre>
     81 
     82 <p class="note">
     83 <b>Note:</b> If multiple pages are listening for onRequest events, only the
     84 first to call sendResponse() for a particular event will succeed in sending the
     85 response. All other responses to that event will be ignored.
     86 </p>
     87 
     88 
     89 <h2 id="connect">Long-lived connections</h2>
     90 <p>
     91 Sometimes it's useful to have a conversation that lasts longer than a single
     92 request and response. In this case, you can open a long-lived channel from
     93 your content script to an extension page, or vice versa, using
     94 <a href="extension.html#method-connect">chrome.extension.connect()</a>
     95 or
     96 <a href="tabs.html#method-connect">chrome.tabs.connect()</a> respectively. The
     97 channel can optionally have a name, allowing you to distinguish between
     98 different types of connections.
     99 
    100 <p>
    101 One use case might be an automatic form fill extension. The content script
    102 could open a channel to the extension page for a particular login, and send a
    103 message to the extension for each input element on the page to request the
    104 form data to fill in. The shared connection allows the extension to keep
    105 shared state linking the several messages coming from the content script.
    106 
    107 <p>
    108 When establishing a connection, each end is given a
    109 <a href="extension.html#type-Port">Port</a>
    110 object which is used for sending and receiving messages through that
    111 connection.
    112 
    113 <p>
    114 Here is how you open a channel from a content script, and send and listen for
    115 messages:
    116 <pre>
    117 contentscript.js
    118 ================
    119 var port = chrome.extension.connect({name: "knockknock"});
    120 port.postMessage({joke: "Knock knock"});
    121 port.onMessage.addListener(function(msg) {
    122   if (msg.question == "Who's there?")
    123     port.postMessage({answer: "Madame"});
    124   else if (msg.question == "Madame who?")
    125     port.postMessage({answer: "Madame... Bovary"});
    126 });
    127 </pre>
    128 
    129 <p>
    130 Sending a request from the extension to a content script looks very similar,
    131 except that you need to specify which tab to connect to. Simply replace the
    132 call to connect in the above example with
    133 <a href="tabs.html#method-connect">chrome.tabs.connect(tabId, {name:
    134 "knockknock"})</a>.
    135 
    136 <p>
    137 In order to handle incoming connections, you need to set up a
    138 <a href="extension.html#event-onConnect">chrome.extension.onConnect</a>
    139 event listener. This looks the same from a content script or an extension
    140 page. When another part of your extension calls "connect()", this event is
    141 fired, along with the
    142 <a href="extension.html#type-Port">Port</a>
    143 object you can use to send and receive messages through the connection. Here's
    144 what it looks like to respond to incoming connections:
    145 <pre>
    146 chrome.extension.onConnect.addListener(function(port) {
    147   console.assert(port.name == "knockknock");
    148   port.onMessage.addListener(function(msg) {
    149     if (msg.joke == "Knock knock")
    150       port.postMessage({question: "Who's there?"});
    151     else if (msg.answer == "Madame")
    152       port.postMessage({question: "Madame who?"});
    153     else if (msg.answer == "Madame... Bovary")
    154       port.postMessage({question: "I don't get it."});
    155   });
    156 });
    157 </pre>
    158 
    159 <p>
    160 You may want to find out when a connection is closed, for example if you are
    161 maintaining separate state for each open port. For this you can listen to the
    162 <a href="extension.html#type-Port">Port.onDisconnect</a>
    163 event. This event is fired either when the other side of the channel manually
    164 calls
    165 <a href="extension.html#type-Port">Port.disconnect()</a>, or when the page
    166 containing the port is unloaded (for example if the tab is navigated).
    167 onDisconnect is guaranteed to be fired only once for any given port.
    168 
    169 
    170 <h2 id="external">Cross-extension messaging</h2>
    171 <p>
    172 In addition to sending messages between different components in your
    173 extension, you can use the messaging API to communicate with other extensions.
    174 This lets you expose a public API that other extensions can take advantage of.
    175 
    176 <p>
    177 Listening for incoming requests and connections is similar to the internal
    178 case, except you use the
    179 <a href="extension.html#event-onRequestExternal">chrome.extension.onRequestExternal</a>
    180 or
    181 <a href="extension.html#event-onConnectExternal">chrome.extension.onConnectExternal</a>
    182 methods. Here's an example of each:
    183 <pre>
    184 // For simple requests:
    185 chrome.extension.onRequestExternal.addListener(
    186   function(request, sender, sendResponse) {
    187     if (sender.id == blacklistedExtension)
    188       sendResponse({});  // don't allow this extension access
    189     else if (request.getTargetData)
    190       sendResponse({targetData: targetData});
    191     else if (request.activateLasers) {
    192       var success = activateLasers();
    193       sendResponse({activateLasers: success});
    194     }
    195   });
    196 
    197 // For long-lived connections:
    198 chrome.extension.onConnectExternal.addListener(function(port) {
    199   port.onMessage.addListener(function(msg) {
    200     // See other examples for sample onMessage handlers.
    201   });
    202 });
    203 </pre>
    204 
    205 <p>
    206 Likewise, sending a message to another extension is similar to sending one
    207 within your extension. The only difference is that you must pass the ID of the
    208 extension you want to communicate with. For example:
    209 <pre>
    210 // The ID of the extension we want to talk to.
    211 var laserExtensionId = "abcdefghijklmnoabcdefhijklmnoabc";
    212 
    213 // Make a simple request:
    214 chrome.extension.sendRequest(laserExtensionId, {getTargetData: true},
    215   function(response) {
    216     if (targetInRange(response.targetData))
    217       chrome.extension.sendRequest(laserExtensionId, {activateLasers: true});
    218   });
    219 
    220 // Start a long-running conversation:
    221 var port = chrome.extension.connect(laserExtensionId);
    222 port.postMessage(...);
    223 </pre>
    224 
    225 <h2 id="security-considerations">Security considerations</h2>
    226 
    227 <p>
    228 When receiving a message from a content script or another extension, your
    229 background page should be careful not to fall victim to <a
    230 href="http://en.wikipedia.org/wiki/Cross-site_scripting">cross-site
    231 scripting</a>.  Specifically, avoid using dangerous APIs such as the
    232 below:
    233 </p>
    234 <pre>background.html
    235 ===============
    236 chrome.tabs.sendRequest(tab.id, {greeting: "hello"}, function(response) {
    237   // WARNING! Might be evaluating an evil script!
    238   var resp = eval("(" + response.farewell + ")");
    239 });
    240 
    241 background.html
    242 ===============
    243 chrome.tabs.sendRequest(tab.id, {greeting: "hello"}, function(response) {
    244   // WARNING! Might be injecting a malicious script!
    245   document.getElementById("resp").innerHTML = response.farewell;
    246 });
    247 </pre>
    248 <p>
    249 Instead, prefer safer APIs that do not run scripts:
    250 </p>
    251 <pre>background.html
    252 ===============
    253 chrome.tabs.sendRequest(tab.id, {greeting: "hello"}, function(response) {
    254   // JSON.parse does not evaluate the attacker's scripts.
    255   var resp = JSON.parse(response.farewell);
    256 });
    257 
    258 background.html
    259 ===============
    260 chrome.tabs.sendRequest(tab.id, {greeting: "hello"}, function(response) {
    261   // innerText does not let the attacker inject HTML elements.
    262   document.getElementById("resp").innerText = response.farewell;
    263 });
    264 </pre>
    265 
    266 <h2 id="examples">Examples</h2>
    267 
    268 <p>
    269 You can find simple examples of communication via messages in the
    270 <a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/messaging/">examples/api/messaging</a>
    271 directory.
    272 Also see the
    273 <a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/howto/contentscript_xhr">contentscript_xhr</a> example,
    274 in which a content script and its parent extension exchange messages,
    275 so that the parent extension can perform
    276 cross-site requests on behalf of the content script.
    277 For more examples and for help in viewing the source code, see
    278 <a href="samples.html">Samples</a>.
    279 </p>
    280