Bug 1736924 - create one-time migration for alwaysAsk mimetype prefs to saveToDisk if downloads improvements pref is enabled. r=Gijs

Differential Revision: https://phabricator.services.mozilla.com/D130136
This commit is contained in:
Katherine Patenio 2021-11-17 23:31:24 +00:00
parent 0958039f60
commit cf8aa80ecf
4 changed files with 322 additions and 2 deletions

View file

@ -25,6 +25,16 @@ ChromeUtils.defineModuleGetter(
"JSONFile",
"resource://gre/modules/JSONFile.jsm"
);
const { Integration } = ChromeUtils.import(
"resource://gre/modules/Integration.jsm"
);
/* global DownloadIntegration */
Integration.downloads.defineModuleGetter(
this,
"DownloadIntegration",
"resource://gre/modules/DownloadIntegration.jsm"
);
XPCOMUtils.defineLazyServiceGetter(
this,
@ -80,6 +90,11 @@ HandlerService.prototype = {
this._migrateProtocolHandlersIfNeeded();
Services.obs.notifyObservers(null, "handlersvc-store-initialized");
// Bug 1736924: run migration for browser.download.improvements_to_download_panel if applicable.
// Since we need DownloadsViewInternally to verify mimetypes, we run this after
// DownloadsViewInternally is registered via the 'handlersvc-store-initialized' notification.
this._migrateDownloadsImprovementsIfNeeded();
}
},
@ -90,6 +105,7 @@ HandlerService.prototype = {
defaultHandlersVersion: {},
mimeTypes: {},
schemes: {},
isDownloadsImprovementsAlreadyMigrated: false,
};
},
@ -393,6 +409,50 @@ HandlerService.prototype = {
}
},
/**
* Update already existing handlers for non-internal mimetypes to have prefs set from alwaysAsk
* to saveToDisk. However, if reading an internal mimetype and set to alwaysAsk, update to use handleInternally.
* This migration is needed since browser.download.improvements_to_download_panel does not
* override user preferences if preferredAction = alwaysAsk. By doing so, we can ensure that file prompt
* behaviours remain consistent for most files.
*
* See Bug 1736924 for more information.
*/
_migrateDownloadsImprovementsIfNeeded() {
// Migrate if the preference is enabled AND if the migration has never been run before.
// Otherwise, we risk overwriting preferences for existing profiles!
if (
Services.prefs.getBoolPref(
"browser.download.improvements_to_download_panel"
) &&
!Services.policies.getActivePolicies()?.Handlers &&
!this._store.data.isDownloadsImprovementsAlreadyMigrated
) {
for (let [type, mimeInfo] of Object.entries(this._store.data.mimeTypes)) {
let isViewableInternally = DownloadIntegration.shouldViewDownloadInternally(
type
);
let isAskOnly = mimeInfo && mimeInfo.ask;
if (isAskOnly) {
if (isViewableInternally) {
mimeInfo.action = Ci.nsIHandlerInfo.handleInternally;
} else {
mimeInfo.action = Ci.nsIHandlerInfo.saveToDisk;
}
// Sets alwaysAskBeforeHandling to false. Needed to ensure that:
// preferredAction appears as expected in preferences table; and
// downloads behaviour is updated to never show UCT window.
mimeInfo.ask = false;
}
}
this._store.data.isDownloadsImprovementsAlreadyMigrated = true;
this._store.saveSoon();
}
},
// nsIHandlerService
enumerate() {
let handlers = Cc["@mozilla.org/array;1"].createInstance(

View file

@ -86,5 +86,6 @@
}
]
}
}
},
"isDownloadsImprovementsAlreadyMigrated": true
}

View file

@ -0,0 +1,251 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
const handlerSvc = Cc["@mozilla.org/uriloader/handler-service;1"].getService(
Ci.nsIHandlerService
);
const mimeSvc = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
const { Integration } = ChromeUtils.import(
"resource://gre/modules/Integration.jsm"
);
/* global DownloadIntegration */
Integration.downloads.defineModuleGetter(
this,
"DownloadIntegration",
"resource://gre/modules/DownloadIntegration.jsm"
);
/**
* Tests that the migration does not run if the pref
* browser.download.improvements_to_download_panel is disabled.
*/
add_task(async function test_migration_pref_disabled() {
registerCleanupFunction(async function() {
Services.prefs.clearUserPref(
"browser.download.improvements_to_download_panel"
);
});
Services.prefs.setBoolPref(
"browser.download.improvements_to_download_panel",
false
);
// Plain text file
let txtHandlerInfo = mimeSvc.getFromTypeAndExtension("text/plain", "txt");
txtHandlerInfo.preferredAction = Ci.nsIHandlerInfo.alwaysAsk;
txtHandlerInfo.alwaysAskBeforeHandling = true;
// PDF file
let pdfHandlerInfo = mimeSvc.getFromTypeAndExtension(
"application/pdf",
"pdf"
);
// When the downloads pref is disabled, HandlerService.store defaults the
// preferredAction from alwaysAsk to useHelperApp for compatibility reasons.
pdfHandlerInfo.preferredAction = Ci.nsIHandlerInfo.useHelperApp;
pdfHandlerInfo.alwaysAskBeforeHandling = true;
handlerSvc.store(txtHandlerInfo);
handlerSvc.store(pdfHandlerInfo);
gHandlerService.wrappedJSObject._migrateDownloadsImprovementsIfNeeded();
txtHandlerInfo = mimeSvc.getFromTypeAndExtension("text/plain", "txt");
pdfHandlerInfo = mimeSvc.getFromTypeAndExtension("application/pdf", "pdf");
let data = gHandlerService.wrappedJSObject._store.data;
Assert.equal(
data.isDownloadsImprovementsAlreadyMigrated,
false,
"isDownloadsImprovementsAlreadyMigrated should be set to false"
);
Assert.notEqual(
pdfHandlerInfo.preferredAction,
Ci.nsIHandlerInfo.saveToDisk,
"application/pdf - preferredAction should not be saveToDisk"
);
Assert.equal(
txtHandlerInfo.preferredAction,
Ci.nsIHandlerInfo.useHelperApp,
"text/plain - preferredAction should be useHelperApp"
);
Assert.equal(
txtHandlerInfo.alwaysAskBeforeHandling,
true,
"text/plain - alwaysAskBeforeHandling should be true"
);
});
/**
* Tests that the migration runs if the pref
* browser.download.improvements_to_download_panel is enabled and
* that only files with preferredAction alwaysAsk are updated.
*/
add_task(async function test_migration_pref_enabled() {
// Create mock implementation of shouldDownloadInternally for test case
let oldShouldViewDownloadInternally =
DownloadIntegration.shouldViewDownloadInternally;
DownloadIntegration.shouldViewDownloadInternally = (mimeType, extension) => {
let downloadTypesViewableInternally = [
{
extension: "pdf",
mimeTypes: ["application/pdf"],
},
{
extension: "svg",
mimeTypes: ["image/svg+xml"],
},
];
for (const mockHandler of downloadTypesViewableInternally) {
if (mockHandler.mimeTypes.includes(mimeType)) {
return true;
}
}
return false;
};
registerCleanupFunction(async function() {
Services.prefs.clearUserPref(
"browser.download.improvements_to_download_panel"
);
DownloadIntegration.shouldViewDownloadInternally = oldShouldViewDownloadInternally;
});
// For setup, set pref to false. Will be enabled later.
Services.prefs.setBoolPref(
"browser.download.improvements_to_download_panel",
false
);
// Plain text file
let txtHandlerInfo = mimeSvc.getFromTypeAndExtension("text/plain", "txt");
txtHandlerInfo.preferredAction = Ci.nsIHandlerInfo.alwaysAsk;
txtHandlerInfo.alwaysAskBeforeHandling = true;
// PDF file
let pdfHandlerInfo = mimeSvc.getFromTypeAndExtension(
"application/pdf",
"pdf"
);
pdfHandlerInfo.preferredAction = Ci.nsIHandlerInfo.alwaysAsk;
pdfHandlerInfo.alwaysAskBeforeHandling = true;
// SVG file
let svgHandlerInfo = mimeSvc.getFromTypeAndExtension("image/svg+xml", "svg");
svgHandlerInfo.preferredAction = Ci.nsIHandlerInfo.useSystemDefault;
svgHandlerInfo.alwaysAskBeforeHandling = false;
handlerSvc.store(txtHandlerInfo);
handlerSvc.store(pdfHandlerInfo);
handlerSvc.store(svgHandlerInfo);
Services.prefs.setBoolPref(
"browser.download.improvements_to_download_panel",
true
);
gHandlerService.wrappedJSObject._migrateDownloadsImprovementsIfNeeded();
txtHandlerInfo = mimeSvc.getFromTypeAndExtension("text/plain", "txt");
pdfHandlerInfo = mimeSvc.getFromTypeAndExtension("application/pdf", "pdf");
svgHandlerInfo = mimeSvc.getFromTypeAndExtension("image/svg+xml", "svg");
let data = gHandlerService.wrappedJSObject._store.data;
Assert.equal(
data.isDownloadsImprovementsAlreadyMigrated,
true,
"isDownloadsImprovementsAlreadyMigrated should be set to true"
);
Assert.equal(
pdfHandlerInfo.preferredAction,
Ci.nsIHandlerInfo.handleInternally,
"application/pdf - preferredAction should be handleInternally"
);
Assert.equal(
pdfHandlerInfo.alwaysAskBeforeHandling,
false,
"application/pdf - alwaysAskBeforeHandling should be false"
);
Assert.equal(
svgHandlerInfo.preferredAction,
Ci.nsIHandlerInfo.useSystemDefault,
"image/svg+xml - preferredAction should be useSystemDefault"
);
Assert.equal(
pdfHandlerInfo.alwaysAskBeforeHandling,
false,
"image/svg+xml - alwaysAskBeforeHandling should be false"
);
Assert.equal(
txtHandlerInfo.preferredAction,
Ci.nsIHandlerInfo.saveToDisk,
"text/plain - preferredAction should be saveToDisk"
);
Assert.equal(
txtHandlerInfo.alwaysAskBeforeHandling,
false,
"text/plain - alwaysAskBeforeHandling should be false"
);
});
/**
* Tests that the migration does not run if the pref
* browser.download.improvements_to_download_panel is enabled but
* the migration was already run.
*/
add_task(async function test_migration_pref_enabled_already_run() {
registerCleanupFunction(async function() {
Services.prefs.clearUserPref(
"browser.download.improvements_to_download_panel"
);
});
Services.prefs.setBoolPref(
"browser.download.improvements_to_download_panel",
true
);
let data = gHandlerService.wrappedJSObject._store.data;
data.isDownloadsImprovementsAlreadyMigrated = true;
// Plain text file
let txtHandlerInfo = mimeSvc.getFromTypeAndExtension("text/plain", "txt");
txtHandlerInfo.preferredAction = Ci.nsIHandlerInfo.alwaysAsk;
txtHandlerInfo.alwaysAskBeforeHandling = true;
// PDF file
let pdfHandlerInfo = mimeSvc.getFromTypeAndExtension(
"application/pdf",
"pdf"
);
pdfHandlerInfo.preferredAction = Ci.nsIHandlerInfo.alwaysAsk;
pdfHandlerInfo.alwaysAskBeforeHandling = true;
handlerSvc.store(txtHandlerInfo);
handlerSvc.store(pdfHandlerInfo);
gHandlerService.wrappedJSObject._migrateDownloadsImprovementsIfNeeded();
txtHandlerInfo = mimeSvc.getFromTypeAndExtension("text/plain", "txt");
pdfHandlerInfo = mimeSvc.getFromTypeAndExtension("application/pdf", "pdf");
data = gHandlerService.wrappedJSObject._store.data;
Assert.equal(
pdfHandlerInfo.preferredAction,
Ci.nsIHandlerInfo.alwaysAsk,
"application/pdf - preferredAction should be alwaysAsk"
);
Assert.equal(
pdfHandlerInfo.alwaysAskBeforeHandling,
true,
"application/pdf - alwaysAskBeforeHandling should be true"
);
Assert.equal(
txtHandlerInfo.preferredAction,
Ci.nsIHandlerInfo.alwaysAsk,
"text/plain - preferredAction should be alwaysAsk"
);
Assert.equal(
txtHandlerInfo.alwaysAskBeforeHandling,
true,
"text/plain - alwaysAskBeforeHandling should be true"
);
});

View file

@ -6,7 +6,15 @@ firefox-appdir = browser
[test_defaults_handlerService.js]
# No default stored handlers on android given lack of support.
# No default stored handlers on Thunderbird.
skip-if = os == "android" || appname == "thunderbird"
skip-if =
os == "android"
appname == "thunderbird"
[test_downloads_improvements_migration.js]
# No default stored handlers on android given lack of support.
# No default stored handlers on Thunderbird.
skip-if =
os == "android"
appname == "thunderbird"
[test_getFromTypeAndExtension.js]
[test_getMIMEInfo_pdf.js]
[test_getMIMEInfo_unknown_mime_type.js]