Bug 1286746 - Invoke sendMessage callback even if there are no listeners
MozReview-Commit-ID: HLIC3ZRcwRm
--- a/toolkit/components/extensions/ExtensionUtils.jsm
+++ b/toolkit/components/extensions/ExtensionUtils.jsm
@@ -1195,16 +1195,18 @@ function getMessageManager(target) {
// getSender(context, messageManagerTarget, sender): returns a MessageSender
// See https://developer.chrome.com/extensions/runtime#type-MessageSender.
function Messenger(context, messageManagers, sender, filter, delegate) {
this.context = context;
this.messageManagers = messageManagers;
this.sender = sender;
this.filter = filter;
this.delegate = delegate;
+
+ MessageChannel.setupMessageManagers(messageManagers);
}
Messenger.prototype = {
_sendMessage(messageManager, message, data, recipient) {
let options = {
recipient,
sender: this.sender,
responseType: MessageChannel.RESPONSE_FIRST,
--- a/toolkit/components/extensions/MessageChannel.jsm
+++ b/toolkit/components/extensions/MessageChannel.jsm
@@ -333,16 +333,32 @@ this.MessageChannel = {
* If multiple message managers matching the specified recipient tag
* are listening for a message, all listeners are notified, and all
* responses are returned as an array, once all listeners have
* replied.
*/
RESPONSE_ALL: 2,
/**
+ * Initializes message handlers for the given message managers if needed.
+ *
+ * @param {[nsIMessageSender]} messageManagers
+ */
+ setupMessageManagers(messageManagers) {
+ for (let mm of messageManagers) {
+ // This call initializes a FilteringMessageManager for |mm| if needed.
+ // The FilteringMessageManager must be created to make sure that senders
+ // of messages that expect a reply, such as MessageChannel:Message, do
+ // actually receive a default reply even if there are no explicit message
+ // handlers.
+ this.messageManagers.get(mm);
+ }
+ },
+
+ /**
* Returns true if the peroperties of the `data` object match those in
* the `filter` object. Matching is done on a strict equality basis,
* and the behavior varies depending on the value of the `strict`
* parameter.
*
* @param {object} filter
* The filter object to match against.
* @param {object} data
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_no_receiver.js
@@ -0,0 +1,25 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+add_task(function* test_sendMessage_without_listener() {
+ function background() {
+ browser.runtime.sendMessage("msg").then(reply => {
+ browser.test.assertEq(undefined, reply);
+ browser.test.notifyFail("Did not expect a reply to sendMessage");
+ }, error => {
+ browser.test.assertEq("Could not establish connection. Receiving end does not exist.", error.message);
+ browser.test.notifyPass("sendMessage callback was invoked");
+ });
+ }
+ let extensionData = {
+ background,
+ };
+
+ let extension = ExtensionTestUtils.loadExtension(extensionData);
+ yield extension.startup();
+
+ yield extension.awaitFinish("sendMessage callback was invoked");
+
+ yield extension.unload();
+});
--- a/toolkit/components/extensions/test/xpcshell/xpcshell.ini
+++ b/toolkit/components/extensions/test/xpcshell/xpcshell.ini
@@ -31,16 +31,17 @@ skip-if = os == "android"
[test_ext_json_parser.js]
[test_ext_localStorage.js]
[test_ext_manifest_content_security_policy.js]
[test_ext_manifest_incognito.js]
[test_ext_onmessage_removelistener.js]
[test_ext_runtime_connect_no_receiver.js]
[test_ext_runtime_getPlatformInfo.js]
[test_ext_runtime_sendMessage.js]
+[test_ext_runtime_sendMessage_no_receiver.js]
[test_ext_schemas.js]
[test_ext_simple.js]
[test_ext_storage.js]
[test_getAPILevelForWindow.js]
[test_locale_converter.js]
[test_locale_data.js]
[test_native_messaging.js]
skip-if = os == "android"