Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(810)

Side by Side Diff: chrome/renderer/resources/extensions/miscellaneous_bindings.js

Issue 9965005: Deprecate chrome.extension.sendRequest in favor of sendMessage, with a safer (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: better docs Created 8 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 // This script contains unprivileged javascript APIs related to chrome 5 // This script contains unprivileged javascript APIs related to chrome
6 // extensions. It is loaded by any extension-related context, such as content 6 // extensions. It is loaded by any extension-related context, such as content
7 // scripts or background pages. 7 // scripts or background pages.
8 // See user_script_slave.cc for script that is loaded by content scripts only. 8 // See user_script_slave.cc for script that is loaded by content scripts only.
9 9
10 require('json_schema'); 10 require('json_schema');
11 require('event_bindings'); 11 require('event_bindings');
12 var miscNatives = requireNative('miscellaneous_bindings'); 12 var miscNatives = requireNative('miscellaneous_bindings');
13 var CloseChannel = miscNatives.CloseChannel; 13 var CloseChannel = miscNatives.CloseChannel;
14 var PortAddRef = miscNatives.PortAddRef; 14 var PortAddRef = miscNatives.PortAddRef;
15 var PortRelease = miscNatives.PortRelease; 15 var PortRelease = miscNatives.PortRelease;
16 var PostMessage = miscNatives.PostMessage; 16 var PostMessage = miscNatives.PostMessage;
17 var BindToGC = miscNatives.BindToGC; 17 var BindToGC = miscNatives.BindToGC;
18 18
19 var chromeHidden = requireNative('chrome_hidden').GetChromeHidden(); 19 var chromeHidden = requireNative('chrome_hidden').GetChromeHidden();
20 var manifestVersion; 20 var manifestVersion;
21 var extensionId; 21 var extensionId;
22 22
23 // The reserved channel name for the sendRequest API. 23 // The reserved channel name for the sendRequest/sendMessage APIs.
24 // Note: sendRequest is deprecated.
24 chromeHidden.kRequestChannel = "chrome.extension.sendRequest"; 25 chromeHidden.kRequestChannel = "chrome.extension.sendRequest";
26 chromeHidden.kMessageChannel = "chrome.extension.sendMessage";
25 27
26 // Map of port IDs to port object. 28 // Map of port IDs to port object.
27 var ports = {}; 29 var ports = {};
28 30
29 // Map of port IDs to chromeHidden.onUnload listeners. Keep track of these 31 // Map of port IDs to chromeHidden.onUnload listeners. Keep track of these
30 // to free the onUnload listeners when ports are closed. 32 // to free the onUnload listeners when ports are closed.
31 var portReleasers = {}; 33 var portReleasers = {};
32 34
33 // Change even to odd and vice versa, to get the other side of a given 35 // Change even to odd and vice versa, to get the other side of a given
34 // channel. 36 // channel.
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
88 } 90 }
89 var port = new PortImpl(portId, opt_name); 91 var port = new PortImpl(portId, opt_name);
90 ports[portId] = port; 92 ports[portId] = port;
91 portReleasers[portId] = PortRelease.bind(this, portId); 93 portReleasers[portId] = PortRelease.bind(this, portId);
92 chromeHidden.onUnload.addListener(portReleasers[portId]); 94 chromeHidden.onUnload.addListener(portReleasers[portId]);
93 95
94 PortAddRef(portId); 96 PortAddRef(portId);
95 return port; 97 return port;
96 }; 98 };
97 99
100 // Helper function for dispatchOnConnect.
101 function handleSendRequestError(isSendMessage, responseCallbackAccessed,
102 sourceExtensionId, targetExtensionId) {
103 var errorMsg;
104 var eventName = (isSendMessage ?
105 "chrome.extension.onMessage" : "chrome.extension.onRequest");
106 if (isSendMessage && !responseCallbackAccessed) {
107 errorMsg =
108 "The " + eventName + " listener must return true if you want to" +
109 " send a response after the listener returns ";
110 } else {
111 errorMsg =
112 "Cannot send a response more than once per " + eventName +
113 " listener per document";
114 }
115 errorMsg += " (message was sent by extension " + sourceExtensionId;
116 if (sourceExtensionId != targetExtensionId)
117 errorMsg += " for extension " + targetExtensionId;
118 errorMsg += ").";
119
120 chrome.extension.lastError = {"message": errorMsg};
121 console.error("Could not send response: " + errorMsg);
122 }
123
98 // Called by native code when a channel has been opened to this context. 124 // Called by native code when a channel has been opened to this context.
99 chromeHidden.Port.dispatchOnConnect = function(portId, channelName, tab, 125 chromeHidden.Port.dispatchOnConnect = function(portId, channelName, tab,
100 sourceExtensionId, 126 sourceExtensionId,
101 targetExtensionId) { 127 targetExtensionId) {
102 // Only create a new Port if someone is actually listening for a connection. 128 // Only create a new Port if someone is actually listening for a connection.
103 // In addition to being an optimization, this also fixes a bug where if 2 129 // In addition to being an optimization, this also fixes a bug where if 2
104 // channels were opened to and from the same process, closing one would 130 // channels were opened to and from the same process, closing one would
105 // close both. 131 // close both.
106 if (targetExtensionId != extensionId) 132 if (targetExtensionId != extensionId)
107 return; // not for us 133 return; // not for us
108 if (ports[getOppositePortId(portId)]) 134 if (ports[getOppositePortId(portId)])
109 return; // this channel was opened by us, so ignore it 135 return; // this channel was opened by us, so ignore it
110 136
111 // Determine whether this is coming from another extension, so we can use 137 // Determine whether this is coming from another extension, so we can use
112 // the right event. 138 // the right event.
113 var isExternal = sourceExtensionId != extensionId; 139 var isExternal = sourceExtensionId != extensionId;
114 140
115 if (tab) 141 if (tab)
116 tab = chromeHidden.JSON.parse(tab); 142 tab = chromeHidden.JSON.parse(tab);
117 var sender = {tab: tab, id: sourceExtensionId}; 143 var sender = {tab: tab, id: sourceExtensionId};
118 144
119 // Special case for sendRequest/onRequest. 145 // Special case for sendRequest/onRequest and sendMessage/onMessage.
120 if (channelName == chromeHidden.kRequestChannel) { 146 var isSendMessage = channelName == chromeHidden.kMessageChannel;
121 var requestEvent = (isExternal ? 147 if (channelName == chromeHidden.kRequestChannel ||
122 chrome.extension.onRequestExternal : chrome.extension.onRequest); 148 channelName == chromeHidden.kMessageChannel) {
149 var requestEvent = (isSendMessage ?
Aaron Boodman 2012/03/30 21:28:00 O_o
Matt Perry 2012/03/30 23:02:48 Yeah I went there.
150 (isExternal ?
151 chrome.extension.onMessageExternal : chrome.extension.onMessage) :
152 (isExternal ?
153 chrome.extension.onRequestExternal : chrome.extension.onRequest));
123 if (requestEvent.hasListeners()) { 154 if (requestEvent.hasListeners()) {
124 var port = chromeHidden.Port.createPort(portId, channelName); 155 var port = chromeHidden.Port.createPort(portId, channelName);
125 port.onMessage.addListener(function(request) { 156 port.onMessage.addListener(function(request) {
157 var responseCallbackAccessed = false;
126 var responseCallback = function(response) { 158 var responseCallback = function(response) {
127 if (port) { 159 if (port) {
128 port.postMessage(response); 160 port.postMessage(response);
129 port = null; 161 port = null;
130 } else { 162 } else {
131 // We nulled out port when sending the response, and now the page 163 // We nulled out port when sending the response, and now the page
132 // is trying to send another response for the same request. 164 // is trying to send another response for the same request.
133 var errorMsg = 165 handleSendRequestError(isSendMessage, responseCallbackAccessed,
134 "Cannot send a response more than once per " + 166 sourceExtensionId, targetExtensionId);
135 "chrome.extension.onRequest listener per document (message " +
136 "was sent by extension " + sourceExtensionId;
137 if (sourceExtensionId != targetExtensionId) {
138 errorMsg += " for extension " + targetExtensionId;
139 }
140 errorMsg += ").";
141 chrome.extension.lastError = {"message": errorMsg};
142 console.error("Could not send response: " + errorMsg);
143 } 167 }
144 }; 168 };
145 // In case the extension never invokes the responseCallback, and also 169 // In case the extension never invokes the responseCallback, and also
146 // doesn't keep a reference to it, we need to clean up the port. Do 170 // doesn't keep a reference to it, we need to clean up the port. Do
147 // so by attaching to the garbage collection of the responseCallback 171 // so by attaching to the garbage collection of the responseCallback
148 // using some native hackery. 172 // using some native hackery.
149 BindToGC(responseCallback, function() { 173 BindToGC(responseCallback, function() {
150 if (port) { 174 if (port) {
151 port.disconnect(); 175 port.disconnect();
152 port = null; 176 port = null;
153 } 177 }
154 }); 178 });
155 requestEvent.dispatch(request, sender, responseCallback); 179 if (!isSendMessage) {
180 requestEvent.dispatch(request, sender, responseCallback);
181 } else {
182 var retvals = requestEvent.dispatch(request, sender,
183 responseCallback);
184 for (var i in retvals) {
185 if (retvals[i] === true) {
186 responseCallbackAccessed = true;
Aaron Boodman 2012/03/30 21:28:00 Were you originally trying to do some craziness wh
Aaron Boodman 2012/03/30 21:28:00 responseCallback = retvals.indexOf(true) > -1;
Matt Perry 2012/03/30 23:02:48 Yep. New name.
Matt Perry 2012/03/30 23:02:48 Sweet, done.
187 break;
188 }
189 }
190 if (!responseCallbackAccessed) {
191 // If they didn't access the response callback, they're not
192 // going to send a response, so clean up the port immediately.
193 port.destroy_();
194 port = null;
195 }
196 }
156 }); 197 });
157 } 198 }
158 return;
159 } 199 }
160 200
161 var connectEvent = (isExternal ? 201 var connectEvent = (isExternal ?
162 chrome.extension.onConnectExternal : chrome.extension.onConnect); 202 chrome.extension.onConnectExternal : chrome.extension.onConnect);
163 if (connectEvent.hasListeners()) { 203 if (connectEvent.hasListeners()) {
164 var port = chromeHidden.Port.createPort(portId, channelName); 204 var port = chromeHidden.Port.createPort(portId, channelName);
165 port.sender = sender; 205 port.sender = sender;
166 if (manifestVersion < 2) 206 if (manifestVersion < 2)
167 port.tab = port.sender.tab; 207 port.tab = port.sender.tab;
168 208
(...skipping 27 matching lines...) Expand all
196 chromeHidden.Port.dispatchOnMessage = function(msg, portId) { 236 chromeHidden.Port.dispatchOnMessage = function(msg, portId) {
197 var port = ports[portId]; 237 var port = ports[portId];
198 if (port) { 238 if (port) {
199 if (msg) { 239 if (msg) {
200 msg = chromeHidden.JSON.parse(msg); 240 msg = chromeHidden.JSON.parse(msg);
201 } 241 }
202 port.onMessage.dispatch(msg, port); 242 port.onMessage.dispatch(msg, port);
203 } 243 }
204 }; 244 };
205 245
246 // Shared implementation used by tabs.sendMessage and extension.sendMessage.
247 chromeHidden.Port.sendMessageImpl = function(port, request,
248 responseCallback) {
249 port.postMessage(request);
250
251 if (port.name == chromeHidden.kMessageChannel && !responseCallback) {
252 // Go ahead and disconnect immediately if the sender is not expecting
253 // a response.
254 port.disconnect();
255 return;
256 }
257
258 if (!responseCallback)
Aaron Boodman 2012/03/30 21:28:00 Maybe add a comment that this is used by the older
Matt Perry 2012/03/30 23:02:48 Done.
259 responseCallback = function() {};
260
261 port.onDisconnect.addListener(function() {
262 // For onDisconnects, we only notify the callback if there was an error
263 try {
264 if (chrome.extension.lastError)
265 responseCallback();
266 } finally {
267 port = null;
268 }
269 });
270 port.onMessage.addListener(function(response) {
271 try {
272 responseCallback(response);
273 } finally {
274 port.disconnect();
275 port = null;
276 }
277 });
278 }
279
206 // This function is called on context initialization for both content scripts 280 // This function is called on context initialization for both content scripts
207 // and extension contexts. 281 // and extension contexts.
208 chromeHidden.onLoad.addListener(function(tempExtensionId, 282 chromeHidden.onLoad.addListener(function(tempExtensionId,
209 isExtensionProcess, 283 isExtensionProcess,
210 inIncognitoContext, 284 inIncognitoContext,
211 tempManifestVersion) { 285 tempManifestVersion) {
212 extensionId = tempExtensionId; 286 extensionId = tempExtensionId;
213 manifestVersion = tempManifestVersion; 287 manifestVersion = tempManifestVersion;
214 288
215 chrome.extension = chrome.extension || {}; 289 chrome.extension = chrome.extension || {};
216 290
217 if (manifestVersion < 2) { 291 if (manifestVersion < 2) {
218 chrome.self = chrome.extension; 292 chrome.self = chrome.extension;
219 chrome.extension.inIncognitoTab = inIncognitoContext; 293 chrome.extension.inIncognitoTab = inIncognitoContext;
220 } 294 }
221 295
222 chrome.extension.inIncognitoContext = inIncognitoContext; 296 chrome.extension.inIncognitoContext = inIncognitoContext;
223 }); 297 });
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698