Home | History | Annotate | Download | only in articles
      1 <h1>Message Passing</h1>
      2 
      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 $ref:runtime.sendMessage
     31 or
     32 $ref:tabs.sendMessage
     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.runtime.sendMessage({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.query({active: true, currentWindow: true}, function(tabs) {
     56   chrome.tabs.sendMessage(tabs[0].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 $ref:runtime.onMessage
     65 event listener to handle the message. This looks the same from a content
     66 script or extension page.
     67 <pre>
     68 chrome.runtime.onMessage.addListener(
     69   function(request, sender, sendResponse) {
     70     console.log(sender.tab ?
     71                 "from a content script:" + sender.tab.url :
     72                 "from the extension");
     73     if (request.greeting == "hello")
     74       sendResponse({farewell: "goodbye"});
     75   });
     76 </pre>
     77 
     78 <p class="note">
     79 <b>Note:</b> If multiple pages are listening for onMessage events, only the
     80 first to call sendResponse() for a particular event will succeed in sending the
     81 response. All other responses to that event will be ignored.
     82 </p>
     83 
     84 
     85 <h2 id="connect">Long-lived connections</h2>
     86 <p>
     87 Sometimes it's useful to have a conversation that lasts longer than a single
     88 request and response. In this case, you can open a long-lived channel from
     89 your content script to an extension page, or vice versa, using
     90 $ref:runtime.connect
     91 or
     92 $ref:tabs.connect respectively. The
     93 channel can optionally have a name, allowing you to distinguish between
     94 different types of connections.
     95 
     96 <p>
     97 One use case might be an automatic form fill extension. The content script
     98 could open a channel to the extension page for a particular login, and send a
     99 message to the extension for each input element on the page to request the
    100 form data to fill in. The shared connection allows the extension to keep
    101 shared state linking the several messages coming from the content script.
    102 
    103 <p>
    104 When establishing a connection, each end is given a
    105 $ref:runtime.Port
    106 object which is used for sending and receiving messages through that
    107 connection.
    108 
    109 <p>
    110 Here is how you open a channel from a content script, and send and listen for
    111 messages:
    112 <pre>
    113 contentscript.js
    114 ================
    115 var port = chrome.runtime.connect({name: "knockknock"});
    116 port.postMessage({joke: "Knock knock"});
    117 port.onMessage.addListener(function(msg) {
    118   if (msg.question == "Who's there?")
    119     port.postMessage({answer: "Madame"});
    120   else if (msg.question == "Madame who?")
    121     port.postMessage({answer: "Madame... Bovary"});
    122 });
    123 </pre>
    124 
    125 <p>
    126 Sending a request from the extension to a content script looks very similar,
    127 except that you need to specify which tab to connect to. Simply replace the
    128 call to connect in the above example with
    129 $ref:tabs.connect.
    130 
    131 <p>
    132 In order to handle incoming connections, you need to set up a
    133 $ref:runtime.onConnect
    134 event listener. This looks the same from a content script or an extension
    135 page. When another part of your extension calls "connect()", this event is
    136 fired, along with the
    137 $ref:runtime.Port
    138 object you can use to send and receive messages through the connection. Here's
    139 what it looks like to respond to incoming connections:
    140 <pre>
    141 chrome.runtime.onConnect.addListener(function(port) {
    142   console.assert(port.name == "knockknock");
    143   port.onMessage.addListener(function(msg) {
    144     if (msg.joke == "Knock knock")
    145       port.postMessage({question: "Who's there?"});
    146     else if (msg.answer == "Madame")
    147       port.postMessage({question: "Madame who?"});
    148     else if (msg.answer == "Madame... Bovary")
    149       port.postMessage({question: "I don't get it."});
    150   });
    151 });
    152 </pre>
    153 
    154 <p>
    155 You may want to find out when a connection is closed, for example if you are
    156 maintaining separate state for each open port. For this you can listen to the
    157 $ref:runtime.Port.onDisconnect
    158 event. This event is fired either when the other side of the channel manually
    159 calls
    160 $ref:runtime.Port.disconnect, or when the page
    161 containing the port is unloaded (for example if the tab is navigated).
    162 onDisconnect is guaranteed to be fired only once for any given port.
    163 
    164 
    165 <h2 id="external">Cross-extension messaging</h2>
    166 <p>
    167 In addition to sending messages between different components in your
    168 extension, you can use the messaging API to communicate with other extensions.
    169 This lets you expose a public API that other extensions can take advantage of.
    170 
    171 <p>
    172 Listening for incoming requests and connections is similar to the internal
    173 case, except you use the
    174 $ref:runtime.onMessageExternal
    175 or
    176 $ref:runtime.onConnectExternal
    177 methods. Here's an example of each:
    178 <pre>
    179 // For simple requests:
    180 chrome.runtime.onMessageExternal.addListener(
    181   function(request, sender, sendResponse) {
    182     if (sender.id == blacklistedExtension)
    183       return;  // don't allow this extension access
    184     else if (request.getTargetData)
    185       sendResponse({targetData: targetData});
    186     else if (request.activateLasers) {
    187       var success = activateLasers();
    188       sendResponse({activateLasers: success});
    189     }
    190   });
    191 
    192 // For long-lived connections:
    193 chrome.runtime.onConnectExternal.addListener(function(port) {
    194   port.onMessage.addListener(function(msg) {
    195     // See other examples for sample onMessage handlers.
    196   });
    197 });
    198 </pre>
    199 
    200 <p>
    201 Likewise, sending a message to another extension is similar to sending one
    202 within your extension. The only difference is that you must pass the ID of the
    203 extension you want to communicate with. For example:
    204 <pre>
    205 // The ID of the extension we want to talk to.
    206 var laserExtensionId = "abcdefghijklmnoabcdefhijklmnoabc";
    207 
    208 // Make a simple request:
    209 chrome.runtime.sendMessage(laserExtensionId, {getTargetData: true},
    210   function(response) {
    211     if (targetInRange(response.targetData))
    212       chrome.runtime.sendMessage(laserExtensionId, {activateLasers: true});
    213   });
    214 
    215 // Start a long-running conversation:
    216 var port = chrome.runtime.connect(laserExtensionId);
    217 port.postMessage(...);
    218 </pre>
    219 
    220 
    221 <h2 id="external-webpage">Sending messages from web pages</h2>
    222 <p>
    223 Similar to <a href="#external">cross-extension messaging</a>,
    224 your app or extension can receive and
    225 respond to messages from regular web pages.
    226 To use this feature, you must first
    227 specify in your manifest.json which web sites you want to communicate with. For
    228 example:
    229 
    230 <pre>
    231 "externally_connectable": {
    232   "matches": ["*://*.example.com/*"]
    233 }
    234 </pre>
    235 
    236 <p>
    237 This will expose the messaging API to any page which matches the URL patterns
    238 you specify. The URL pattern must contain at least a
    239 <a href="http://en.wikipedia.org/wiki/Second-level_domain">second-level domain</a>
    240 - that is, hostname
    241 patterns like "*", "*.com", "*.co.uk", and "*.appspot.com" are prohibited.
    242 From the web page, use the
    243 $ref:runtime.sendMessage
    244 or
    245 $ref:runtime.connect
    246 APIs to send a message to a specific app or extension. For example:
    247 <pre>
    248 // The ID of the extension we want to talk to.
    249 var editorExtensionId = "abcdefghijklmnoabcdefhijklmnoabc";
    250 
    251 // Make a simple request:
    252 chrome.runtime.sendMessage(editorExtensionId, {openUrlInEditor: url},
    253   function(response) {
    254     if (!response.success)
    255       handleError(url);
    256   });
    257 </pre>
    258 
    259 <p>
    260 From your app or extension, you may listen to messages from web pages via the
    261 $ref:runtime.onMessageExternal
    262 or
    263 $ref:runtime.onConnectExternal
    264 APIs, similar to <a href="#external">cross-extension messaging</a>.
    265 Only the web page can initiate a connection.
    266 Here is an example:
    267 
    268 <pre>
    269 chrome.runtime.onMessageExternal.addListener(
    270   function(request, sender, sendResponse) {
    271     if (sender.url == blacklistedWebsite)
    272       return;  // don't allow this web page access
    273     if (request.openUrlInEditor)
    274       openUrl(request.openUrlInEditor);
    275   });
    276 </pre>
    277 
    278 
    279 <h2 id="native-messaging">Native messaging</h2>
    280 <p>
    281 Extensions can exchange messages with native applications. Native
    282 applications that support this feature must register a <em>native messaging
    283 host</em> that knows how to communicate with the extension. Chrome starts the
    284 host in a separate process and communicates with it using standard input and
    285 standard output streams.
    286 
    287 <h3 id="native-messaging-host">Native messaging host</h3>
    288 <p>
    289 In order to register a native messaging host the application must install a
    290 manifest file that defines native messaging host configuration. Below is an
    291 example of the manifest file:
    292 <pre>{
    293   "name": "com.my_company.my_application",
    294   "description": "My Application",
    295   "path": "C:\Program Files\My Application\chrome_native_messaging_host.exe",
    296   "type": "stdio",
    297   "allowed_origins": [
    298     "chrome-extension://knldjmfmopnpolahpmmgbagdohdnhkik/"
    299   ]
    300 }
    301 </pre>
    302 
    303 <p>Native messaging host manifest file contains the following fields:
    304 <table class="simple">
    305   <tr>
    306     <th>Name</th>
    307     <th>Description</th>
    308   </tr>
    309   <tr>
    310     <td><code>name</code></td>
    311     <td>Native messaging host name.</td>
    312   </tr>
    313   <tr>
    314     <td><code>description</code></td>
    315     <td>Short application description.</td>
    316   </tr>
    317   <tr>
    318     <td><code>path</code></td>
    319     <td>Path to the native messaging host binary. On Linux and OSX the path must
    320     be absolute. On Windows it can be relative to the directory in which the
    321     manifest file is located.</td>
    322   </tr>
    323   <tr>
    324     <td><code>type</code></td>
    325     <td>Type of the interface used to communicate with the native messaging
    326     host. Currently there is only one possible value for this parameter:
    327     <code>stdio</code>. It indicates that Chrome should use <code>stdin</code>
    328     and <code>stdout</code> to communicate with the host.</td>
    329   </tr>
    330   <tr>
    331     <td><code>allowed_origins</code></td>
    332     <td>List of extensions that should have access to the native messaging host.</td>
    333   </tr>
    334 </table>
    335 
    336 <p>Location of the manifest file depends on the platform:
    337 
    338 <dl>
    339   <dt>Windows:</dt>
    340     <dd>The manifest file can be located anywhere in the file system.
    341      The application installer must create registry key
    342      <code>HKEY_LOCAL_MACHINE\SOFTWARE\Google\Chrome\NativeMessagingHosts\<em>host_name</em></code>
    343      and set default value of that key to the full path to the manifest file.
    344     </dd>
    345 
    346   <dt>OSX:</dt>
    347     <dd>The manifest file must be placed at
    348     <code>/Library/Google/Chrome/NativeMessagingHosts/<em>host_name</em>.json</code>
    349     </dd>
    350   <dt>Linux:</dt>
    351     <dd>The manifest file must be placed at
    352     <code>/etc/opt/chrome/native-messaging-hosts/<em>host_name</em>.json</code>
    353     </dd>
    354 </dl>
    355 
    356 <p>
    357 Chrome starts each native messaging host in a separate process and communicates
    358 with it using standard input (<code>stdin</code>) and standard output
    359 (<code>stdout</code>). The same format is used to send messages in both
    360 directions: each message is serialized using JSON, UTF-8 encoded
    361 and is preceded with 32-bit message length in native byte order.
    362 
    363 <h3 id="native-messaging-client">Connecting to a native application</h3>
    364 <p>
    365 Sending and receiving messages to and from a native application is very similar
    366 to cross-extension messaging. The main difference is that
    367 $ref:runtime.connectNative is used instead of $ref:runtime.connect,
    368 and $ref:runtime.sendNativeMessage is used instead of $ref:runtime.sendMessage.
    369 
    370 <p>
    371 The Following example creates a $ref:runtime.Port object that's connected to native
    372 messaging host <code>com.my_company.my_application</code>, starts listening for
    373 messages from that port and sends one outgoing message:
    374 <pre>
    375 var port = chrome.runtime.connectNative('com.my_company.my_application');
    376 port.onMessage.addListener(function(msg) {
    377   console.log("Received" + msg);
    378 });
    379 port.onDisconnect.addListener(function() {
    380   console.log("Disconnected");
    381 });
    382 port.postMessage({ text: "Hello, my_application" });
    383 </pre>
    384 
    385 <p>
    386 $ref:runtime.sendNativeMessage can be used to send a message to native
    387 application without creating a port, e.g.:
    388 <pre>
    389 chrome.runtime.sendNativeMessage('com.my_company.my_application',
    390   { text: "Hello" },
    391   function(response) {
    392     console.log("Received " + response);
    393   });
    394 </pre>
    395 
    396 <h2 id="security-considerations">Security considerations</h2>
    397 
    398 <p>
    399 When receiving a message from a content script or another extension, your
    400 background page should be careful not to fall victim to <a
    401 href="http://en.wikipedia.org/wiki/Cross-site_scripting">cross-site
    402 scripting</a>.  Specifically, avoid using dangerous APIs such as the
    403 below:
    404 </p>
    405 <pre>background.html
    406 ===============
    407 chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
    408   // WARNING! Might be evaluating an evil script!
    409   var resp = eval("(" + response.farewell + ")");
    410 });
    411 
    412 background.html
    413 ===============
    414 chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
    415   // WARNING! Might be injecting a malicious script!
    416   document.getElementById("resp").innerHTML = response.farewell;
    417 });
    418 </pre>
    419 <p>
    420 Instead, prefer safer APIs that do not run scripts:
    421 </p>
    422 <pre>background.html
    423 ===============
    424 chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
    425   // JSON.parse does not evaluate the attacker's scripts.
    426   var resp = JSON.parse(response.farewell);
    427 });
    428 
    429 background.html
    430 ===============
    431 chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
    432   // innerText does not let the attacker inject HTML elements.
    433   document.getElementById("resp").innerText = response.farewell;
    434 });
    435 </pre>
    436 
    437 <h2 id="examples">Examples</h2>
    438 
    439 <p>
    440 You can find simple examples of communication via messages in the
    441 <a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/messaging/">examples/api/messaging</a>
    442 directory.
    443 <a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/nativeMessaging/">examples/api/nativeMessaging</a>
    444 contains an example application that uses native messaging.
    445 Also see the
    446 <a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/howto/contentscript_xhr">contentscript_xhr</a> example,
    447 in which a content script and its parent extension exchange messages,
    448 so that the parent extension can perform
    449 cross-site requests on behalf of the content script.
    450 For more examples and for help in viewing the source code, see
    451 <a href="samples.html">Samples</a>.
    452 </p>
    453