Chromium Code Reviews| 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 ? |
|
Aaron Boodman
2012/03/30 21:28:00
O_o
Matt Perry
2012/03/30 23:02:48
Yeah I went there.
|
| + (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; |
|
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.
|
| + 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) |
|
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.
|
| + 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, |