Bug 1286746 - Invoke sendMessage callback even if there are no listeners. r=kmag
☠☠ backed out by 4f78b9f4278f ☠ ☠
authorRob Wu <rob@robwu.nl>
Thu, 14 Jul 2016 20:34:40 -0700
changeset 332031 26f41a685662f89b35dd7a10f8fba0ab128a7c2d
parent 332030 a34d250bea8e25d273a9f2239a5f155d0844551c
child 332032 562910144a3a32a69af4957e52d250df5a83136e
push id9858
push userjlund@mozilla.com
push dateMon, 01 Aug 2016 14:37:10 +0000
treeherdermozilla-aurora@203106ef6cb6 [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/mochitest/mochitest.ini
toolkit/components/extensions/test/mochitest/test_ext_runtime_sendMessage_no_receiver.html
--- a/toolkit/components/extensions/ExtensionUtils.jsm
+++ b/toolkit/components/extensions/ExtensionUtils.jsm
@@ -1191,16 +1191,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
--- a/toolkit/components/extensions/test/mochitest/mochitest.ini
+++ b/toolkit/components/extensions/test/mochitest/mochitest.ini
@@ -65,16 +65,17 @@ skip-if = (os == 'android' || buildapp =
 [test_ext_runtime_connect_twoway.html]
 skip-if = (os == 'android' || buildapp == 'b2g') # port.sender.tab is undefined on b2g. Bug 1258975 on android.
 [test_ext_runtime_connect2.html]
 skip-if = (os == 'android' || buildapp == 'b2g') # port.sender.tab is undefined on b2g. Bug 1258975 on android.
 [test_ext_runtime_disconnect.html]
 [test_ext_runtime_getPlatformInfo.html]
 [test_ext_runtime_id.html]
 [test_ext_runtime_sendMessage.html]
+[test_ext_runtime_sendMessage_no_receiver.html]
 [test_ext_sandbox_var.html]
 [test_ext_sendmessage_reply.html]
 skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2g. Bug 1258975 on android.
 [test_ext_sendmessage_reply2.html]
 skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2g. Bug 1258975 on android.
 [test_ext_sendmessage_doublereply.html]
 skip-if = (os == 'android' || buildapp == 'b2g') # sender.tab is undefined on b2g. Bug 1258975 on android.
 [test_ext_storage.html]
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/mochitest/test_ext_runtime_sendMessage_no_receiver.html
@@ -0,0 +1,38 @@
+<!DOCTYPE HTML>
+<html>
+<head>
+  <title>WebExtension test</title>
+  <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
+  <script type="text/javascript" src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
+  <script type="text/javascript" src="head.js"></script>
+  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css">
+</head>
+<body>
+
+<script>
+"use strict";
+
+add_task(function* test_sendMessage_without_listener() {
+  function backgroundScript() {
+    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: `(${backgroundScript})();`,
+  };
+
+  let extension = ExtensionTestUtils.loadExtension(extensionData);
+  yield extension.startup();
+
+  yield extension.awaitFinish("sendMessage callback was invoked");
+
+  yield extension.unload();
+});
+</script>
+</body>