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