Bug 286746 - 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
@@ -1027,26 +1027,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) {
throw new this.context.contentWindow.Error("Attempt to disconnect() a disconnected port");
}
this.handleDisconnection();
this.messageManager.sendAsyncMessage(this.disconnectName);
@@ -1156,18 +1160,22 @@ Messenger.prototype = {
};
}).api();
},
connect(messageManager, name, recipient) {
let portId = nextPortId++;
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 => {
+ if (e.result == MessageChannel.RESULT_NO_HANDLER) {
+ port.disconnectByOtherEnd();
+ }
+ });
return port.api();
},
onConnect(name) {
return new SingletonEventManager(this.context, name, callback => {
let listener = {
messageFilterPermissive: this.filter,
--- a/toolkit/components/extensions/test/mochitest/mochitest.ini
+++ b/toolkit/components/extensions/test/mochitest/mochitest.ini
@@ -55,16 +55,17 @@ skip-if = buildapp == 'b2g' # runat != d
[test_ext_idle.html]
[test_ext_localStorage.html]
[test_ext_onmessage_removelistener.html]
[test_ext_notifications.html]
[test_ext_permission_xhr.html]
skip-if = buildapp == 'b2g' # JavaScript error: jar:remoteopenfile:///data/local/tmp/generated-extension.xpi!/content.js, line 46: NS_ERROR_ILLEGAL_VALUE:
[test_ext_runtime_connect.html]
skip-if = (os == 'android' || buildapp == 'b2g') # port.sender.tab is undefined on b2g. Bug 1258975 on android.
+[test_ext_runtime_connect_no_receiver.html]
[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]
new file mode 100644
--- /dev/null
+++ b/toolkit/components/extensions/test/mochitest/test_ext_runtime_connect_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_connect_without_listener() {
+ function backgroundScript() {
+ let port = browser.runtime.connect();
+ port.onDisconnect.addListener(() => {
+ browser.test.notifyPass("port.onDisconnect was called");
+ });
+ }
+ let extensionData = {
+ background: `(${backgroundScript})();`,
+ manifest: {},
+ };
+
+ let extension = ExtensionTestUtils.loadExtension(extensionData);
+ yield extension.startup();
+ info("extension loaded");
+
+ yield extension.awaitFinish("port.onDisconnect was called");
+
+ yield extension.unload();
+ info("extension unloaded");
+});
+</script>
+</body>