Bug 1731898 - Change protocol handling logic for non-standard cases r=Gijs

Differential Revision: https://phabricator.services.mozilla.com/D141859
This commit is contained in:
Sarah Clements 2022-04-26 10:01:31 +00:00
parent 6e2c6b51eb
commit 096901dbf5
3 changed files with 79 additions and 9 deletions

View File

@ -111,6 +111,8 @@ const kSafeSchemes = [
"xmpp",
];
const STANDARD_SAFE_PROTOCOLS = kSafeSchemes;
// Note that even if the scheme fits the criteria for a web-handled scheme
// (ie it is compatible with the checks registerProtocolHandler uses), it may
// not be web-handled - it could still be handled via the OS by another app.
@ -275,6 +277,7 @@ var E10SUtils = {
PRIVILEGEDMOZILLA_REMOTE_TYPE,
FISSION_WEB_REMOTE_TYPE,
SERVICEWORKER_REMOTE_TYPE,
STANDARD_SAFE_PROTOCOLS,
/**
* @param aURI The URI of the about page

View File

@ -8,6 +8,9 @@ const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
const { E10SUtils } = ChromeUtils.import(
"resource://gre/modules/E10SUtils.jsm"
);
const DIALOG_URL_APP_CHOOSER =
"chrome://mozapps/content/handling/appChooser.xhtml";
@ -310,12 +313,14 @@ class nsContentDispatchChooser {
}
let shouldOpenHandler = false;
try {
shouldOpenHandler = await this._prompt(
aHandler,
aPrincipal,
callerHasPermission,
aBrowsingContext
aBrowsingContext,
aURI
);
} catch (error) {
Cu.reportError(error.message);
@ -358,9 +363,31 @@ class nsContentDispatchChooser {
* @param {BrowsingContext} [aBrowsingContext] - Context associated with the
* protocol navigation.
*/
async _prompt(aHandler, aPrincipal, aHasPermission, aBrowsingContext) {
async _prompt(aHandler, aPrincipal, aHasPermission, aBrowsingContext, aURI) {
let shouldOpenHandler = false;
let resetHandlerChoice = false;
let updateHandlerData = false;
const isStandardProtocol = E10SUtils.STANDARD_SAFE_PROTOCOLS.includes(
aURI.scheme
);
const {
hasDefaultHandler,
preferredApplicationHandler,
alwaysAskBeforeHandling,
} = aHandler;
// This will skip the app chooser dialog flow unless the user explicitly opts to choose
// another app in the permission dialog.
if (
!isStandardProtocol &&
hasDefaultHandler &&
preferredApplicationHandler == null &&
alwaysAskBeforeHandling
) {
aHandler.alwaysAskBeforeHandling = false;
updateHandlerData = true;
}
// If caller does not have permission, prompt the user.
if (!aHasPermission) {
@ -446,14 +473,17 @@ class nsContentDispatchChooser {
]) {
aHandler[prop] = outArgs.getProperty(prop);
}
// Store handler data
Cc["@mozilla.org/uriloader/handler-service;1"]
.getService(Ci.nsIHandlerService)
.store(aHandler);
updateHandlerData = true;
}
}
if (updateHandlerData) {
// Store handler data
Cc["@mozilla.org/uriloader/handler-service;1"]
.getService(Ci.nsIHandlerService)
.store(aHandler);
}
return shouldOpenHandler;
}

View File

@ -3,6 +3,10 @@
"use strict";
var { AppConstants } = ChromeUtils.import(
"resource://gre/modules/AppConstants.jsm"
);
let gHandlerService = Cc["@mozilla.org/uriloader/handler-service;1"].getService(
Ci.nsIHandlerService
);
@ -71,7 +75,6 @@ function initTestHandlers() {
let handlerInfo = HandlerServiceTestUtils.getBlankHandlerInfo(scheme);
handlerInfo.possibleApplicationHandlers.appendElement(webHandler);
handlerInfo.preferredApplicationHandler = webHandler;
gHandlerService.store(handlerInfo);
});
}
@ -128,6 +131,7 @@ async function triggerOpenProto(
useJSRedirect = false,
serverRedirect = "",
linkToRedirect = false,
customHandlerInfo,
} = {}
) {
let uri = `${scheme}://test`;
@ -169,7 +173,8 @@ async function triggerOpenProto(
"@mozilla.org/content-dispatch-chooser;1"
].createInstance(Ci.nsIContentDispatchChooser);
let handler = HandlerServiceTestUtils.getHandlerInfo(scheme);
let handler =
customHandlerInfo || HandlerServiceTestUtils.getHandlerInfo(scheme);
contentDispatchChooser.handleURI(
handler,
@ -328,6 +333,7 @@ async function testOpenProto(
// Check the button label depending on whether we would show the chooser
// dialog next or directly open the handler.
let acceptBtnLabel = dialogEl.getButton("accept")?.label;
if (chooserIsNext) {
is(
acceptBtnLabel,
@ -832,6 +838,37 @@ add_task(async function test_no_principal() {
});
});
/**
* Tests that if a URI scheme has a non-standard protocol, an OS default exists,
* and the user hasn't selected an alternative only the permission dialog is shown.
*/
add_task(async function test_non_standard_protocol() {
let scheme = null;
// TODO add a scheme for Windows 10 or greater once support is added (see bug 1764599).
if (AppConstants.platform == "macosx") {
scheme = "itunes";
} else {
info(
"Skipping this test since there isn't a suitable default protocol on this platform"
);
return;
}
await BrowserTestUtils.withNewTab(ORIGIN1, async browser => {
await testOpenProto(browser, scheme, {
loadOptions: {
customHandlerInfo: HandlerServiceTestUtils.getHandlerInfo(scheme),
},
permDialogOptions: {
hasCheckbox: true,
hasChangeApp: true,
chooserIsNext: false,
actionChangeApp: false,
},
});
});
});
/**
* Tests that we skip the permission dialog for extension callers.
*/