commit f22505510c37019f14bdeb676b63989e64787469
parent 2f46db151480d329d3512befea4df75ccf6538c7
Author: Sarah Clements <sclements@mozilla.com>
Date: Wed, 22 Oct 2025 17:21:21 +0000
Bug 1972326 - Permission should show when opening external helper app r=Gijs
* Improve _hasProtocolHandlerPermission to handle external + non-standard protocol + hasHelper scenario
* Add test case and move protocol helper into head.js
Differential Revision: https://phabricator.services.mozilla.com/D268142
Diffstat:
4 files changed, 71 insertions(+), 18 deletions(-)
diff --git a/toolkit/mozapps/handling/ContentDispatchChooser.sys.mjs b/toolkit/mozapps/handling/ContentDispatchChooser.sys.mjs
@@ -45,10 +45,14 @@ export class nsContentDispatchChooser {
aBrowsingContext,
aTriggeredExternally = false
) {
+ const isStandardProtocol = E10SUtils.STANDARD_SAFE_PROTOCOLS.includes(
+ aURI.scheme
+ );
let callerHasPermission = this._hasProtocolHandlerPermission(
- aHandler.type,
+ aHandler,
aPrincipal,
- aTriggeredExternally
+ aTriggeredExternally,
+ isStandardProtocol
);
// Force showing the dialog for links passed from outside the application.
@@ -276,11 +280,18 @@ export class nsContentDispatchChooser {
* @param {nsIPrincipal} aPrincipal - Principal to test for permission.
* @returns {boolean} - true if permission is set, false otherwise.
*/
- _hasProtocolHandlerPermission(scheme, aPrincipal, aTriggeredExternally) {
+ _hasProtocolHandlerPermission(
+ aHandler,
+ aPrincipal,
+ aTriggeredExternally,
+ isStandardProtocol
+ ) {
// If a handler is set to open externally by default we skip the dialog.
+ const { type, hasDefaultHandler, preferredApplicationHandler } = aHandler;
+
if (
Services.prefs.getBoolPref(
- "network.protocol-handler.external." + scheme,
+ "network.protocol-handler.external." + type,
false
)
) {
@@ -289,12 +300,16 @@ export class nsContentDispatchChooser {
if (
!aPrincipal ||
- (aPrincipal.isSystemPrincipal && !aTriggeredExternally)
+ (aPrincipal.isSystemPrincipal && !aTriggeredExternally) ||
+ (!isStandardProtocol &&
+ hasDefaultHandler &&
+ !preferredApplicationHandler &&
+ aTriggeredExternally)
) {
return false;
}
- let key = this._getSkipProtoDialogPermissionKey(scheme);
+ let key = this._getSkipProtoDialogPermissionKey(type);
return (
Services.perms.testPermissionFromPrincipal(aPrincipal, key) ===
Services.perms.ALLOW_ACTION
diff --git a/uriloader/exthandler/tests/mochitest/browser_protocol_ask_dialog_external.js b/uriloader/exthandler/tests/mochitest/browser_protocol_ask_dialog_external.js
@@ -197,3 +197,40 @@ add_task(async function external_https_redirect_doesnt_ask() {
);
gHandlerService.wrappedJSObject.mockProtocolHandler();
});
+
+/**
+ * Tests that if a URI scheme is launched externally, has a non-standard protocol
+ * and a default exists the permission dialog is shown.
+ */
+add_task(async function test_external_non_standard_protocol() {
+ let scheme = getSystemProtocol();
+ if (!scheme) {
+ return;
+ }
+ let uri = `${scheme}://test`;
+ let cmdLineHandler = Cc["@mozilla.org/browser/final-clh;1"].getService(
+ Ci.nsICommandLineHandler
+ );
+ let permissionDialogOpenPromise = waitForProtocolPermissionDialog(
+ gBrowser,
+ true
+ );
+ let fakeCmdLine = Cu.createCommandLine(
+ ["-url", uri],
+ null,
+ Ci.nsICommandLine.STATE_REMOTE_EXPLICIT
+ );
+ cmdLineHandler.handle(fakeCmdLine);
+ let dialog = await permissionDialogOpenPromise;
+ ok(dialog, "Should have prompted.");
+
+ let dialogClosedPromise = waitForProtocolPermissionDialog(
+ gBrowser.selectedBrowser,
+ false
+ );
+ let dialogEl = dialog._frame.contentDocument.querySelector("dialog");
+ dialogEl.cancelDialog();
+ await dialogClosedPromise;
+ // We will have opened a tab; close it.
+ BrowserTestUtils.removeTab(gBrowser.selectedTab);
+});
diff --git a/uriloader/exthandler/tests/mochitest/browser_protocol_ask_dialog_permission.js b/uriloader/exthandler/tests/mochitest/browser_protocol_ask_dialog_permission.js
@@ -61,18 +61,6 @@ function getSkipProtoDialogPermissionKey(aProtocolScheme) {
);
}
-function getSystemProtocol() {
- // TODO add a scheme for Windows 10 or greater once support is added (see bug 1764599).
- if (AppConstants.platform == "macosx") {
- return "itunes";
- }
-
- info(
- "Skipping this test since there isn't a suitable default protocol on this platform"
- );
- return null;
-}
-
/**
* Creates dummy web protocol handlers used for testing.
*/
diff --git a/uriloader/exthandler/tests/mochitest/head.js b/uriloader/exthandler/tests/mochitest/head.js
@@ -570,3 +570,16 @@ function runExtProtocolSandboxTest(options) {
}
);
}
+
+function getSystemProtocol() {
+ if (AppConstants.platform == "macosx") {
+ return "itunes";
+ } else if (AppConstants.platform == "win") {
+ return "mms";
+ }
+
+ info(
+ "Skipping this test since there isn't a suitable default protocol on this platform"
+ );
+ return null;
+}