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