Bug 1286746 - Invoke sendMessage callback even if there are no listeners. r=kmag
authorRob Wu <rob@robwu.nl>
Thu, 14 Jul 2016 20:34:40 -0700
changeset 333351 02afaa4b6e393c3798bf767bb86c82d30fcb0ccf
parent 333350 c208ce0321e8891ff81c35d64cca89dc977f8b1d
child 333352 d4130ffb32090902cb050aab0ed302784c39dd2a
push id10033
push userraliiev@mozilla.com
push dateMon, 19 Sep 2016 13:50:26 +0000
treeherdermozilla-aurora@5dddbefdf759 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerskmag
bugs1286746
milestone50.0a1
Bug 1286746 - Invoke sendMessage callback even if there are no listeners. r=kmag MozReview-Commit-ID: HLIC3ZRcwRm
toolkit/components/extensions/ExtensionUtils.jsm
toolkit/components/extensions/MessageChannel.jsm
toolkit/components/extensions/test/xpcshell/test_ext_runtime_sendMessage_no_receiver.js
toolkit/components/extensions/test/xpcshell/xpcshell.ini
--- 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
@@ -33,16 +33,17 @@ skip-if = os == "android"
 [test_ext_manifest_content_security_policy.js]
 [test_ext_manifest_incognito.js]
 [test_ext_native_messaging.js]
 skip-if = os == "android"
 [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"