| Index: chrome/renderer/resources/extensions/miscellaneous_bindings.js
|
| diff --git a/chrome/renderer/resources/extensions/miscellaneous_bindings.js b/chrome/renderer/resources/extensions/miscellaneous_bindings.js
|
| index 84556f3b14cc07c26058beae8140586bacdf948f..b20d34d14276eb1c20c03e7dcb3163c44a5acaf3 100644
|
| --- a/chrome/renderer/resources/extensions/miscellaneous_bindings.js
|
| +++ b/chrome/renderer/resources/extensions/miscellaneous_bindings.js
|
| @@ -20,8 +20,10 @@
|
| var manifestVersion;
|
| var extensionId;
|
|
|
| - // The reserved channel name for the sendRequest API.
|
| + // The reserved channel name for the sendRequest/sendMessage APIs.
|
| + // Note: sendRequest is deprecated.
|
| chromeHidden.kRequestChannel = "chrome.extension.sendRequest";
|
| + chromeHidden.kMessageChannel = "chrome.extension.sendMessage";
|
|
|
| // Map of port IDs to port object.
|
| var ports = {};
|
| @@ -95,6 +97,30 @@
|
| return port;
|
| };
|
|
|
| + // Helper function for dispatchOnConnect.
|
| + function handleSendRequestError(isSendMessage, responseCallbackAccessed,
|
| + sourceExtensionId, targetExtensionId) {
|
| + var errorMsg;
|
| + var eventName = (isSendMessage ?
|
| + "chrome.extension.onMessage" : "chrome.extension.onRequest");
|
| + if (isSendMessage && !responseCallbackAccessed) {
|
| + errorMsg =
|
| + "The " + eventName + " listener must return true if you want to" +
|
| + " send a response after the listener returns ";
|
| + } else {
|
| + errorMsg =
|
| + "Cannot send a response more than once per " + eventName +
|
| + " listener per document";
|
| + }
|
| + errorMsg += " (message was sent by extension " + sourceExtensionId;
|
| + if (sourceExtensionId != targetExtensionId)
|
| + errorMsg += " for extension " + targetExtensionId;
|
| + errorMsg += ").";
|
| +
|
| + chrome.extension.lastError = {"message": errorMsg};
|
| + console.error("Could not send response: " + errorMsg);
|
| + }
|
| +
|
| // Called by native code when a channel has been opened to this context.
|
| chromeHidden.Port.dispatchOnConnect = function(portId, channelName, tab,
|
| sourceExtensionId,
|
| @@ -116,13 +142,19 @@
|
| tab = chromeHidden.JSON.parse(tab);
|
| var sender = {tab: tab, id: sourceExtensionId};
|
|
|
| - // Special case for sendRequest/onRequest.
|
| - if (channelName == chromeHidden.kRequestChannel) {
|
| - var requestEvent = (isExternal ?
|
| - chrome.extension.onRequestExternal : chrome.extension.onRequest);
|
| + // Special case for sendRequest/onRequest and sendMessage/onMessage.
|
| + var isSendMessage = channelName == chromeHidden.kMessageChannel;
|
| + if (channelName == chromeHidden.kRequestChannel ||
|
| + channelName == chromeHidden.kMessageChannel) {
|
| + var requestEvent = (isSendMessage ?
|
| + (isExternal ?
|
| + chrome.extension.onMessageExternal : chrome.extension.onMessage) :
|
| + (isExternal ?
|
| + chrome.extension.onRequestExternal : chrome.extension.onRequest));
|
| if (requestEvent.hasListeners()) {
|
| var port = chromeHidden.Port.createPort(portId, channelName);
|
| port.onMessage.addListener(function(request) {
|
| + var responseCallbackAccessed = false;
|
| var responseCallback = function(response) {
|
| if (port) {
|
| port.postMessage(response);
|
| @@ -130,16 +162,8 @@
|
| } else {
|
| // We nulled out port when sending the response, and now the page
|
| // is trying to send another response for the same request.
|
| - var errorMsg =
|
| - "Cannot send a response more than once per " +
|
| - "chrome.extension.onRequest listener per document (message " +
|
| - "was sent by extension " + sourceExtensionId;
|
| - if (sourceExtensionId != targetExtensionId) {
|
| - errorMsg += " for extension " + targetExtensionId;
|
| - }
|
| - errorMsg += ").";
|
| - chrome.extension.lastError = {"message": errorMsg};
|
| - console.error("Could not send response: " + errorMsg);
|
| + handleSendRequestError(isSendMessage, responseCallbackAccessed,
|
| + sourceExtensionId, targetExtensionId);
|
| }
|
| };
|
| // In case the extension never invokes the responseCallback, and also
|
| @@ -152,10 +176,26 @@
|
| port = null;
|
| }
|
| });
|
| - requestEvent.dispatch(request, sender, responseCallback);
|
| + if (!isSendMessage) {
|
| + requestEvent.dispatch(request, sender, responseCallback);
|
| + } else {
|
| + var retvals = requestEvent.dispatch(request, sender,
|
| + responseCallback);
|
| + for (var i in retvals) {
|
| + if (retvals[i] === true) {
|
| + responseCallbackAccessed = true;
|
| + break;
|
| + }
|
| + }
|
| + if (!responseCallbackAccessed) {
|
| + // If they didn't access the response callback, they're not
|
| + // going to send a response, so clean up the port immediately.
|
| + port.destroy_();
|
| + port = null;
|
| + }
|
| + }
|
| });
|
| }
|
| - return;
|
| }
|
|
|
| var connectEvent = (isExternal ?
|
| @@ -203,6 +243,40 @@
|
| }
|
| };
|
|
|
| + // Shared implementation used by tabs.sendMessage and extension.sendMessage.
|
| + chromeHidden.Port.sendMessageImpl = function(port, request,
|
| + responseCallback) {
|
| + port.postMessage(request);
|
| +
|
| + if (port.name == chromeHidden.kMessageChannel && !responseCallback) {
|
| + // Go ahead and disconnect immediately if the sender is not expecting
|
| + // a response.
|
| + port.disconnect();
|
| + return;
|
| + }
|
| +
|
| + if (!responseCallback)
|
| + responseCallback = function() {};
|
| +
|
| + port.onDisconnect.addListener(function() {
|
| + // For onDisconnects, we only notify the callback if there was an error
|
| + try {
|
| + if (chrome.extension.lastError)
|
| + responseCallback();
|
| + } finally {
|
| + port = null;
|
| + }
|
| + });
|
| + port.onMessage.addListener(function(response) {
|
| + try {
|
| + responseCallback(response);
|
| + } finally {
|
| + port.disconnect();
|
| + port = null;
|
| + }
|
| + });
|
| + }
|
| +
|
| // This function is called on context initialization for both content scripts
|
| // and extension contexts.
|
| chromeHidden.onLoad.addListener(function(tempExtensionId,
|
|
|