Bug 1286746 - Invoke port.onDisconnect if there are no onConnect listeners
MozReview-Commit-ID: DPs36oFm25J
--- a/toolkit/components/extensions/ExtensionUtils.jsm
+++ b/toolkit/components/extensions/ExtensionUtils.jsm
@@ -1141,26 +1141,30 @@ Port.prototype = {
handleDisconnection() {
this.messageManager.removeMessageListener(this.disconnectName, this);
this.context.forgetOnClose(this);
this.disconnected = true;
},
receiveMessage(msg) {
if (msg.name == this.disconnectName) {
- if (this.disconnected) {
- return;
- }
+ this.disconnectByOtherEnd();
+ }
+ },
- for (let listener of this.disconnectListeners) {
- listener();
- }
+ disconnectByOtherEnd() {
+ if (this.disconnected) {
+ return;
+ }
- this.handleDisconnection();
+ for (let listener of this.disconnectListeners) {
+ listener();
}
+
+ this.handleDisconnection();
},
disconnect() {
if (this.disconnected) {
// disconnect() may be called without side effects even after the port is
// closed - https://developer.chrome.com/extensions/runtime#type-Port
return;
}
@@ -1275,18 +1279,18 @@ Messenger.prototype = {
}).api();
},
connect(messageManager, name, recipient) {
// TODO(robwu): Use a process ID instead of the process type. bugzil.la/1287626
let portId = `${gNextPortId++}-${Services.appinfo.processType}`;
let port = new Port(this.context, messageManager, name, portId, null);
let msg = {name, portId};
- // TODO: Disconnect the port if no response?
- this._sendMessage(messageManager, "Extension:Connect", msg, recipient);
+ this._sendMessage(messageManager, "Extension:Connect", msg, recipient)
+ .catch(e => port.disconnectByOtherEnd());
return port.api();
},
onConnect(name) {
return new SingletonEventManager(this.context, name, callback => {
let listener = {
messageFilterPermissive: this.filter,
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/xpcshell/test_ext_runtime_connect_no_receiver.js
@@ -0,0 +1,22 @@
+/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */
+/* vim: set sts=2 sw=2 et tw=80: */
+"use strict";
+
+add_task(function* test_connect_without_listener() {
+ function background() {
+ let port = browser.runtime.connect();
+ port.onDisconnect.addListener(() => {
+ browser.test.notifyPass("port.onDisconnect was called");
+ });
+ }
+ let extensionData = {
+ background,
+ };
+
+ let extension = ExtensionTestUtils.loadExtension(extensionData);
+ yield extension.startup();
+
+ yield extension.awaitFinish("port.onDisconnect was called");
+
+ yield extension.unload();
+});
--- a/toolkit/components/extensions/test/xpcshell/xpcshell.ini
+++ b/toolkit/components/extensions/test/xpcshell/xpcshell.ini
@@ -28,16 +28,17 @@ skip-if = os == "android"
skip-if = os == "android"
[test_ext_extension.js]
[test_ext_idle.js]
[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_schemas.js]
[test_ext_simple.js]
[test_ext_storage.js]
[test_getAPILevelForWindow.js]
[test_locale_converter.js]
[test_locale_data.js]