Merge Chromium + Blink git repositories
[chromium-blink-merge.git] / chrome / common / extensions / docs / templates / articles / messaging.html
blob782c3a454d3b0f89964471308b524837f9953b67
1 <h1>Message Passing</h1>
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.
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.
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.
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>
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>
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>
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>
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.
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.
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.
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"});
125 </pre>
127 {{^is_apps}}
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}}
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."});
155 </pre>
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.
168 <h2 id="external">Cross-extension messaging</h2>
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.
175 Listening for incoming requests and connections is similar to the internal
176 case, except you use the
177 $(ref:runtime.onMessageExternal)
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});
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.
201 </pre>
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";
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});
218 // Start a long-running conversation:
219 var port = chrome.runtime.connect(laserExtensionId);
220 port.postMessage(...);
221 </pre>
224 <h2 id="external-webpage">Sending messages from web pages</h2>
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:
233 <pre data-filename="manifest.json">
234 "externally_connectable": {
235 "matches": ["*://*.example.com/*"]
237 </pre>
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)
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";
254 // Make a simple request:
255 chrome.runtime.sendMessage(editorExtensionId, {openUrlInEditor: url},
256 function(response) {
257 if (!response.success)
258 handleError(url);
260 </pre>
263 From your app or extension, you may listen to messages from web pages via the
264 $(ref:runtime.onMessageExternal)
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:
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);
279 </pre>
282 <!-- Anchors to make sure that pages that link to a previous version of the
283 documentation do not break. -->
284 <a id="native-messaging-host"></a>
285 <a id="native-messaging-client"></a>
286 <h2 id="native-messaging">Native messaging</h2>
288 Extensions and apps <a href="nativeMessaging#native-messaging-client">can
289 exchange messages</a> with native applications that are registered as a
290 <a href="nativeMessaging#native-messaging-host">native messaging host</a>.
291 To learn more about this feature, see <a href="nativeMessaging">Native messaging</a>.
294 <h2 id="security-considerations">Security considerations</h2>
297 When receiving a message from a content script or another extension, your
298 background page should be careful not to fall victim to <a
299 href="http://en.wikipedia.org/wiki/Cross-site_scripting">cross-site
300 scripting</a>. Specifically, avoid using dangerous APIs such as the
301 below:
302 </p>
303 <pre data-filename="background.js">
304 chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
305 // WARNING! Might be evaluating an evil script!
306 var resp = eval("(" + response.farewell + ")");
308 </pre>
309 <pre data-filename="background.js">
310 chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
311 // WARNING! Might be injecting a malicious script!
312 document.getElementById("resp").innerHTML = response.farewell;
314 </pre>
316 Instead, prefer safer APIs that do not run scripts:
317 </p>
318 <pre data-filename="background.js">
319 chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
320 // JSON.parse does not evaluate the attacker's scripts.
321 var resp = JSON.parse(response.farewell);
323 </pre>
324 <pre data-filename="background.js">
325 chrome.tabs.sendMessage(tab.id, {greeting: "hello"}, function(response) {
326 // innerText does not let the attacker inject HTML elements.
327 document.getElementById("resp").innerText = response.farewell;
329 </pre>
331 <h2 id="examples">Examples</h2>
334 You can find simple examples of communication via messages in the
335 <a href="http://src.chromium.org/viewvc/chrome/trunk/src/chrome/common/extensions/docs/examples/api/messaging/">examples/api/messaging</a>
336 directory.
337 The <a href="nativeMessaging#examples">native messaging sample</a> demonstrates
338 how a Chrome app can communicate with a native app.
339 For more examples and for help in viewing the source code, see
340 <a href="samples">Samples</a>.
341 </p>