Backed out 4 changesets (bug 1639067) for XPCshell failures in tests/unit/test_getMIMEInfo_pdf.js. CLOSED TREE

Backed out changeset 1e400fafd80b (bug 1639067)
Backed out changeset 7bb3c2ec5c7a (bug 1639067)
Backed out changeset 755fd5771648 (bug 1639067)
Backed out changeset 951e10b7354f (bug 1639067)
This commit is contained in:
Dorel Luca 2020-08-18 00:18:32 +03:00
parent 1bfd4639dc
commit 806d75bb33
22 changed files with 80 additions and 824 deletions

View file

@ -386,11 +386,6 @@ pref("browser.download.openInSystemViewerContextMenuItem", true);
// This records whether or not to show the 'Always open...' context menu item when appropriate
pref("browser.download.alwaysOpenInSystemViewerContextMenuItem", true);
// Open downloaded file types internally for the given types.
// This is a comma-separated list, the empty string ("") means no types are
// viewable internally.
pref("browser.download.viewableInternally.enabledTypes", "xml,svg,webp,avif");
// This controls whether the button is automatically shown/hidden depending
// on whether there are downloads to show.

View file

@ -711,8 +711,6 @@ XPCOMUtils.defineLazyModuleGetters(this, {
Corroborate: "resource://gre/modules/Corroborate.jsm",
Discovery: "resource:///modules/Discovery.jsm",
DoHController: "resource:///modules/DoHController.jsm",
DownloadsViewableInternally:
"resource:///modules/DownloadsViewableInternally.jsm",
ExtensionsUI: "resource:///modules/ExtensionsUI.jsm",
FirefoxMonitor: "resource:///modules/FirefoxMonitor.jsm",
FxAccounts: "resource://gre/modules/FxAccounts.jsm",
@ -1126,10 +1124,6 @@ BrowserGlue.prototype = {
// pdf content handler, and initializes parent side message manager
// shim for privileged api access.
PdfJs.init(this._isNewProfile);
// Allow certain viewable internally types to be opened from downloads.
DownloadsViewableInternally.register();
break;
case "shield-init-complete":
this._shieldInitComplete = true;

View file

@ -311,14 +311,14 @@ class DownloadsSubview extends DownloadsViewUI.BaseView {
"temporary-block",
button.classList.contains("temporary-block")
);
// menu items are conditionally displayed via CSS based on a viewable-internally attribute
// menu items are conditionally displayed via CSS based on an is-pdf attribute
DownloadsCommon.log(
"DownloadsSubview, updateContextMenu, download is viewable internally? ",
"DownloadsSubview, updateContextMenu, download is pdf? ",
download.target.path,
button.hasAttribute("viewable-internally")
button.hasAttribute("is-pdf")
);
if (button.hasAttribute("viewable-internally")) {
menu.setAttribute("viewable-internally", "true");
if (button.hasAttribute("is-pdf")) {
menu.setAttribute("is-pdf", "true");
let alwaysUseSystemViewerItem = menu.querySelector(
".downloadAlwaysUseSystemDefaultMenuItem"
);
@ -339,7 +339,7 @@ class DownloadsSubview extends DownloadsViewUI.BaseView {
DownloadsCommon.openInSystemViewerItemEnabled
);
} else {
menu.removeAttribute("viewable-internally");
menu.removeAttribute("is-pdf");
}
for (let menuitem of menu.getElementsByTagName("menuitem")) {

View file

@ -31,17 +31,6 @@ XPCOMUtils.defineLazyServiceGetter(
"nsIHandlerService"
);
const { Integration } = ChromeUtils.import(
"resource://gre/modules/Integration.jsm"
);
/* global DownloadIntegration */
Integration.downloads.defineModuleGetter(
this,
"DownloadIntegration",
"resource://gre/modules/DownloadIntegration.jsm"
);
const HTML_NS = "http://www.w3.org/1999/xhtml";
var gDownloadElementButtons = {
@ -476,12 +465,11 @@ DownloadsViewUI.DownloadElementShell.prototype = {
// This is a completed download, and the target file still exists.
this.element.setAttribute("exists", "true");
this.element.toggleAttribute(
"viewable-internally",
DownloadIntegration.shouldViewDownloadInternally(
DownloadsCommon.getMimeInfo(this.download)?.type
)
const isPDF = DownloadsCommon.isFileOfType(
this.download,
"application/pdf"
);
this.element.toggleAttribute("is-pdf", isPDF);
let sizeWithUnits = DownloadsViewUI.getSizeWithUnits(this.download);
if (this.isPanel) {
@ -753,9 +741,7 @@ DownloadsViewUI.DownloadElementShell.prototype = {
return this.download.stopped;
case "downloadsCmd_openInSystemViewer":
case "downloadsCmd_alwaysOpenInSystemViewer":
return DownloadIntegration.shouldViewDownloadInternally(
DownloadsCommon.getMimeInfo(this.download)?.type
);
return DownloadsCommon.isFileOfType(this.download, "application/pdf");
}
return DownloadsViewUI.isCommandName(aCommand) && !!this[aCommand];
},

View file

@ -1,351 +0,0 @@
/* 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/. */
/*
* TODO: This is based on what PdfJs was already doing, it would be
* best to use this over there as well to reduce duplication and
* inconsistency.
*/
"use strict";
var EXPORTED_SYMBOLS = [
"DownloadsViewableInternally",
"PREF_ENABLED_TYPES",
"PREF_BRANCH_WAS_REGISTERED",
"PREF_BRANCH_PREVIOUS_ACTION",
"PREF_BRANCH_PREVIOUS_ASK",
];
const { XPCOMUtils } = ChromeUtils.import(
"resource://gre/modules/XPCOMUtils.jsm"
);
const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm");
XPCOMUtils.defineLazyServiceGetter(
this,
"HandlerService",
"@mozilla.org/uriloader/handler-service;1",
"nsIHandlerService"
);
XPCOMUtils.defineLazyServiceGetter(
this,
"MIMEService",
"@mozilla.org/mime;1",
"nsIMIMEService"
);
ChromeUtils.defineModuleGetter(
this,
"Integration",
"resource://gre/modules/Integration.jsm"
);
const PREF_BRANCH = "browser.download.viewableInternally.";
const PREF_ENABLED_TYPES = PREF_BRANCH + "enabledTypes";
const PREF_BRANCH_WAS_REGISTERED = PREF_BRANCH + "typeWasRegistered.";
const PREF_BRANCH_PREVIOUS_ACTION =
PREF_BRANCH + "previousHandler.preferredAction.";
const PREF_BRANCH_PREVIOUS_ASK =
PREF_BRANCH + "previousHandler.alwaysAskBeforeHandling.";
let DownloadsViewableInternally = {
/**
* Initially add/remove handlers, watch pref, register with Integration.downloads.
*/
register() {
// Watch the pref
XPCOMUtils.defineLazyPreferenceGetter(
this,
"_enabledTypes",
PREF_ENABLED_TYPES,
"",
() => this._updateAllHandlers(),
pref => {
let itemStr = pref.trim();
return itemStr ? itemStr.split(",").map(s => s.trim()) : [];
}
);
for (let handlerType of this._downloadTypesViewableInternally) {
if (handlerType.initAvailable) {
handlerType.initAvailable();
}
}
// Initially update handlers
this._updateAllHandlers();
// Register the check for use in DownloadIntegration
Integration.downloads.register(base => ({
shouldViewDownloadInternally: this._shouldViewDownloadInternally.bind(
this
),
}));
},
/**
* MIME types to handle with an internal viewer, for downloaded files.
*
* |extension| is an extenson that will be viewable, as an alternative for
* the MIME type itself. It is also used more generally to identify this
* type: It is part of a pref name to indicate the handler was set up once,
* and it is the string present in |PREF_ENABLED_TYPES| to enable the type.
*
* |mimeTypes| are the types that will be viewable. A handler is set up for
* the first element in the array.
*
* If |managedElsewhere| is falsy, |_updateAllHandlers()| will set
* up or remove handlers for the type, and |_shouldViewDownloadInternally()|
* will check for it in |PREF_ENABLED_TYPES|.
*
* |available| is used to check whether this type should have
* handleInternally handlers set up, and if false then
* |_shouldViewDownloadInternally()| will also return false for this
* type. If |available| would change, |DownloadsViewableInternally._updateHandler()|
* should be called for the type.
*
* |initAvailable()| is an opportunity to initially set |available|, set up
* observers to change it when prefs change, etc.
*
*/
_downloadTypesViewableInternally: [
{
extension: "xml",
mimeTypes: ["text/xml", "application/xml"],
available: true,
},
{
extension: "svg",
mimeTypes: ["image/svg+xml"],
initAvailable() {
XPCOMUtils.defineLazyPreferenceGetter(
this,
"available",
"svg.disabled",
true,
() => DownloadsViewableInternally._updateHandler(this),
// transform disabled to enabled/available
disabledPref => !disabledPref
);
},
// available getter is set by initAvailable()
},
{
extension: "webp",
mimeTypes: ["image/webp"],
initAvailable() {
XPCOMUtils.defineLazyPreferenceGetter(
this,
"available",
"image.webp.enabled",
false,
() => DownloadsViewableInternally._updateHandler(this)
);
},
// available getter is set by initAvailable()
},
{
extension: "avif",
mimeTypes: ["image/avif"],
initAvailable() {
// NOTE: This does not handle MOZ_AV1, which determines whether
// the browser is built with AV1, and therefore AVIF, support.
// When image.avif.enabled is set true by default in
// StaticPrefList.yaml, it should be wrapped in #ifdef MOZ_AV1
XPCOMUtils.defineLazyPreferenceGetter(
this,
"available",
"image.avif.enabled",
false,
() => DownloadsViewableInternally._updateHandler(this)
);
},
// available getter is set by initAvailable()
},
{
extension: "pdf",
mimeTypes: ["application/pdf"],
// PDF uses pdfjs.disabled rather than PREF_ENABLED_TYPES.
// pdfjs.disabled isn't checked here because PdfJs's own _becomeHandler
// and _unbecomeHandler manage the handler if the pref is set, and there
// is an explicit check in nsUnknownContentTypeDialog.shouldShowInternalHandlerOption
available: true,
managedElsewhere: true,
},
],
/*
* Implementation for DownloadIntegration.shouldViewDownloadInternally
*/
_shouldViewDownloadInternally(aMimeType, aExtension) {
if (!aMimeType) {
return false;
}
return this._downloadTypesViewableInternally.some(handlerType => {
if (
!handlerType.managedElsewhere &&
!this._enabledTypes.includes(handlerType.extension)
) {
return false;
}
return (
(handlerType.mimeTypes.includes(aMimeType) ||
handlerType.extension == aExtension?.toLowerCase()) &&
handlerType.available
);
});
},
_makeFakeHandler(aMimeType, aExtension) {
// Based on PdfJs gPdfFakeHandlerInfo.
return {
QueryInterface: ChromeUtils.generateQI(["nsIMIMEInfo"]),
getFileExtensions() {
return [aExtension];
},
possibleApplicationHandlers: Cc["@mozilla.org/array;1"].createInstance(
Ci.nsIMutableArray
),
extensionExists(ext) {
return ext == aExtension;
},
alwaysAskBeforeHandling: false,
preferredAction: Ci.nsIHandlerInfo.handleInternally,
type: aMimeType,
};
},
_saveSettings(handlerInfo, handlerType) {
Services.prefs.setIntPref(
PREF_BRANCH_PREVIOUS_ACTION + handlerType.extension,
handlerInfo.preferredAction
);
Services.prefs.setBoolPref(
PREF_BRANCH_PREVIOUS_ASK + handlerType.extension,
handlerInfo.alwaysAskBeforeHandling
);
},
_restoreSettings(handlerInfo, handlerType) {
const prevActionPref = PREF_BRANCH_PREVIOUS_ACTION + handlerType.extension;
if (Services.prefs.prefHasUserValue(prevActionPref)) {
handlerInfo.alwaysAskBeforeHandling = Services.prefs.getBoolPref(
PREF_BRANCH_PREVIOUS_ASK + handlerType.extension
);
handlerInfo.preferredAction = Services.prefs.getIntPref(prevActionPref);
HandlerService.store(handlerInfo);
} else {
// Nothing to restore, just remove the handler.
HandlerService.remove(handlerInfo);
}
},
_clearSavedSettings(extension) {
Services.prefs.clearUserPref(PREF_BRANCH_PREVIOUS_ACTION + extension);
Services.prefs.clearUserPref(PREF_BRANCH_PREVIOUS_ASK + extension);
},
_updateAllHandlers() {
// Set up or remove handlers for each type, if not done already
for (const handlerType of this._downloadTypesViewableInternally) {
if (!handlerType.managedElsewhere) {
this._updateHandler(handlerType);
}
}
},
_updateHandler(handlerType) {
const wasRegistered = Services.prefs.getBoolPref(
PREF_BRANCH_WAS_REGISTERED + handlerType.extension,
false
);
const toBeRegistered =
this._enabledTypes.includes(handlerType.extension) &&
handlerType.available;
if (toBeRegistered && !wasRegistered) {
this._becomeHandler(handlerType);
} else if (!toBeRegistered && wasRegistered) {
this._unbecomeHandler(handlerType);
}
},
_becomeHandler(handlerType) {
// Set up an empty handler with only a preferred action, to avoid
// having to ask the OS about handlers on startup.
let fakeHandlerInfo = this._makeFakeHandler(
handlerType.mimeTypes[0],
handlerType.extension
);
if (!HandlerService.exists(fakeHandlerInfo)) {
HandlerService.store(fakeHandlerInfo);
} else {
const handlerInfo = MIMEService.getFromTypeAndExtension(
handlerType.mimeTypes[0],
handlerType.extension
);
if (handlerInfo.preferredAction != Ci.nsIHandlerInfo.handleInternally) {
// Save the previous settings of preferredAction and
// alwaysAskBeforeHandling in case we need to revert them.
// Even if we don't force preferredAction here, the user could
// set handleInternally manually.
this._saveSettings(handlerInfo, handlerType);
} else {
// handleInternally shouldn't already have been set, the best we
// can do to restore is to remove the handler, so make sure
// the settings are clear.
this._clearSavedSettings(handlerType.extension);
}
// Replace the preferred action if it didn't indicate an external viewer.
// Note: This is a point of departure from PdfJs, which always replaces
// the preferred action.
if (
handlerInfo.preferredAction != Ci.nsIHandlerInfo.useHelperApp &&
handlerInfo.preferredAction != Ci.nsIHandlerInfo.useSystemDefault
) {
handlerInfo.preferredAction = Ci.nsIHandlerInfo.handleInternally;
handlerInfo.alwaysAskBeforeHandling = false;
HandlerService.store(handlerInfo);
}
}
// Note that we set up for this type so a) we don't keep replacing the
// handler and b) so it can be cleared later.
Services.prefs.setBoolPref(
PREF_BRANCH_WAS_REGISTERED + handlerType.extension,
true
);
},
_unbecomeHandler(handlerType) {
let handlerInfo;
try {
handlerInfo = MIMEService.getFromTypeAndExtension(
handlerType.mimeTypes[0],
handlerType.extension
);
} catch (ex) {
// Allow the handler lookup to fail.
}
// Restore preferred action if it is still handleInternally
// (possibly just removing the handler if nothing was saved for it).
if (handlerInfo?.preferredAction == Ci.nsIHandlerInfo.handleInternally) {
this._restoreSettings(handlerInfo, handlerType);
}
// In any case we do not control this handler now.
this._clearSavedSettings(handlerType.extension);
Services.prefs.clearUserPref(
PREF_BRANCH_WAS_REGISTERED + handlerType.extension
);
},
};

View file

@ -715,8 +715,8 @@ DownloadsPlacesView.prototype = {
contextMenu.setAttribute("exists", "true");
contextMenu.classList.toggle("temporary-block", !!download.hasBlockedData);
if (element.hasAttribute("viewable-internally")) {
contextMenu.setAttribute("viewable-internally", "true");
if (element.hasAttribute("is-pdf")) {
contextMenu.setAttribute("is-pdf", "true");
let alwaysUseSystemViewerItem = contextMenu.querySelector(
".downloadAlwaysUseSystemDefaultMenuItem"
);
@ -737,7 +737,7 @@ DownloadsPlacesView.prototype = {
DownloadsCommon.openInSystemViewerItemEnabled
);
} else {
contextMenu.removeAttribute("viewable-internally");
contextMenu.removeAttribute("is-pdf");
}
if (!download.stopped) {

View file

@ -99,10 +99,10 @@
/* the system-viewer context menu items are only shown for certain mime-types
and can be individually enabled via prefs */
.download-state:not([viewable-internally]) .downloadUseSystemDefaultMenuItem,
.download-state:not([is-pdf]) .downloadUseSystemDefaultMenuItem,
.download-state .downloadUseSystemDefaultMenuItem:not([enabled]),
.download-state .downloadAlwaysUseSystemDefaultMenuItem:not([enabled]),
.download-state:not([viewable-internally]) .downloadAlwaysUseSystemDefaultMenuItem
.download-state:not([is-pdf]) .downloadAlwaysUseSystemDefaultMenuItem
{
display: none;
}

View file

@ -953,8 +953,8 @@ var DownloadsView = {
"temporary-block",
element.classList.contains("temporary-block")
);
if (element.hasAttribute("viewable-internally")) {
contextMenu.setAttribute("viewable-internally", "true");
if (element.hasAttribute("is-pdf")) {
contextMenu.setAttribute("is-pdf", "true");
let alwaysUseSystemViewerItem = contextMenu.querySelector(
".downloadAlwaysUseSystemDefaultMenuItem"
);
@ -975,7 +975,7 @@ var DownloadsView = {
DownloadsCommon.openInSystemViewerItemEnabled
);
} else {
contextMenu.removeAttribute("viewable-internally");
contextMenu.removeAttribute("is-pdf");
}
},

View file

@ -15,7 +15,6 @@ EXTRA_JS_MODULES += [
'DownloadsCommon.jsm',
'DownloadsSubview.jsm',
'DownloadsTaskbar.jsm',
'DownloadsViewableInternally.jsm',
'DownloadsViewUI.jsm',
]
@ -27,4 +26,4 @@ if toolkit == 'cocoa':
with Files('**'):
BUG_COMPONENT = ('Firefox', 'Downloads Panel')
XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']
XPCSHELL_TESTS_MANIFESTS += ['test/unit/xpcshell.ini']

View file

@ -1,252 +0,0 @@
/* Any copyright is dedicated to the Public Domain.
http://creativecommons.org/publicdomain/zero/1.0/ */
const PREF_SVG_DISABLED = "svg.disabled";
const PREF_WEBP_ENABLED = "image.webp.enabled";
const PDF_MIME = "application/pdf";
const OCTET_MIME = "application/octet-stream";
const XML_MIME = "text/xml";
const SVG_MIME = "image/svg+xml";
const WEBP_MIME = "image/webp";
const { Integration } = ChromeUtils.import(
"resource://gre/modules/Integration.jsm"
);
const {
DownloadsViewableInternally,
PREF_ENABLED_TYPES,
PREF_BRANCH_WAS_REGISTERED,
PREF_BRANCH_PREVIOUS_ACTION,
PREF_BRANCH_PREVIOUS_ASK,
} = ChromeUtils.import("resource:///modules/DownloadsViewableInternally.jsm");
/* global DownloadIntegration */
Integration.downloads.defineModuleGetter(
this,
"DownloadIntegration",
"resource://gre/modules/DownloadIntegration.jsm"
);
const HandlerService = Cc[
"@mozilla.org/uriloader/handler-service;1"
].getService(Ci.nsIHandlerService);
const MIMEService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
function checkPreferInternal(mime, ext, expectedPreferInternal) {
const handler = MIMEService.getFromTypeAndExtension(mime, ext);
if (expectedPreferInternal) {
Assert.equal(
handler?.preferredAction,
Ci.nsIHandlerInfo.handleInternally,
`checking ${mime} preferredAction == handleInternally`
);
} else {
Assert.notEqual(
handler?.preferredAction,
Ci.nsIHandlerInfo.handleInternally,
`checking ${mime} preferredAction != handleInternally`
);
}
}
function shouldView(mime, ext) {
return DownloadIntegration.shouldViewDownloadInternally(mime, ext);
}
function checkShouldView(mime, ext, expectedShouldView) {
Assert.equal(
shouldView(mime, ext),
expectedShouldView,
`checking ${mime} shouldViewDownloadInternally`
);
}
function checkWasRegistered(ext, expectedWasRegistered) {
Assert.equal(
Services.prefs.getBoolPref(PREF_BRANCH_WAS_REGISTERED + ext, false),
expectedWasRegistered,
`checking ${ext} was registered pref`
);
}
function checkAll(mime, ext, expected) {
checkPreferInternal(mime, ext, expected);
checkShouldView(mime, ext, expected);
checkWasRegistered(ext, expected);
}
add_task(async function test_viewable_internally() {
Services.prefs.setCharPref(PREF_ENABLED_TYPES, "xml , svg,webp");
Services.prefs.setBoolPref(PREF_SVG_DISABLED, false);
Services.prefs.setBoolPref(PREF_WEBP_ENABLED, true);
checkAll(XML_MIME, "xml", false);
checkAll(SVG_MIME, "svg", false);
checkAll(WEBP_MIME, "webp", false);
DownloadsViewableInternally.register();
checkAll(XML_MIME, "xml", true);
checkAll(SVG_MIME, "svg", true);
checkAll(WEBP_MIME, "webp", true);
// Remove SVG so it won't be cleared
Services.prefs.clearUserPref(PREF_BRANCH_WAS_REGISTERED + "svg");
// Disable xml and svg, check that xml becomes disabled
Services.prefs.setCharPref(PREF_ENABLED_TYPES, "webp");
checkAll(XML_MIME, "xml", false);
checkAll(WEBP_MIME, "webp", true);
// SVG shouldn't be cleared
checkPreferInternal(SVG_MIME, "svg", true);
Assert.ok(
shouldView(PDF_MIME),
"application/pdf should be unaffected by pref"
);
Assert.ok(
shouldView(OCTET_MIME, "pdf"),
".pdf should be accepted by extension"
);
Assert.ok(
shouldView(OCTET_MIME, "PDF"),
".pdf should be detected case-insensitively"
);
Assert.ok(!shouldView(OCTET_MIME, "exe"), ".exe shouldn't be accepted");
Assert.ok(!shouldView(XML_MIME), "text/xml should be disabled by pref");
Assert.ok(!shouldView(SVG_MIME), "image/xml+svg should be disabled by pref");
// Enable, check that everything is enabled again
Services.prefs.setCharPref(PREF_ENABLED_TYPES, "xml,svg,webp");
checkPreferInternal(XML_MIME, "xml", true);
checkPreferInternal(SVG_MIME, "svg", true);
Assert.ok(
shouldView(PDF_MIME),
"application/pdf should be unaffected by pref"
);
Assert.ok(shouldView(XML_MIME), "text/xml should be enabled by pref");
Assert.ok(
shouldView("application/xml"),
"alternate MIME type application/xml should be accepted"
);
Assert.ok(
shouldView(OCTET_MIME, "xml"),
".xml should be accepted by extension"
);
// Disable viewable internally, pre-set handlers.
Services.prefs.setCharPref(PREF_ENABLED_TYPES, "");
for (const [mime, ext, action, ask] of [
[XML_MIME, "xml", Ci.nsIHandlerInfo.useSystemDefault, true],
[SVG_MIME, "svg", Ci.nsIHandlerInfo.saveToDisk, true],
[WEBP_MIME, "webp", Ci.nsIHandlerInfo.saveToDisk, false],
]) {
let handler = MIMEService.getFromTypeAndExtension(mime, ext);
handler.preferredAction = action;
handler.alwaysAskBeforeHandling = ask;
HandlerService.store(handler);
checkPreferInternal(mime, ext, false);
// Expect to read back the same values
handler = MIMEService.getFromTypeAndExtension(mime, ext);
Assert.equal(handler.preferredAction, action);
Assert.equal(handler.alwaysAskBeforeHandling, ask);
}
// Enable viewable internally, XML should not be replaced, SVG and WebP should be saved.
Services.prefs.setCharPref(PREF_ENABLED_TYPES, "svg,webp,xml");
Assert.equal(
Services.prefs.getIntPref(PREF_BRANCH_PREVIOUS_ACTION + "svg"),
Ci.nsIHandlerInfo.saveToDisk,
"svg action should be saved"
);
Assert.equal(
Services.prefs.getBoolPref(PREF_BRANCH_PREVIOUS_ASK + "svg"),
true,
"svg ask should be saved"
);
Assert.equal(
Services.prefs.getIntPref(PREF_BRANCH_PREVIOUS_ACTION + "webp"),
Ci.nsIHandlerInfo.saveToDisk,
"webp action should be saved"
);
Assert.equal(
Services.prefs.getBoolPref(PREF_BRANCH_PREVIOUS_ASK + "webp"),
false,
"webp ask should be saved"
);
{
let handler = MIMEService.getFromTypeAndExtension(XML_MIME, "xml");
Assert.equal(
handler.preferredAction,
Ci.nsIHandlerInfo.useSystemDefault,
"svg action should be preserved"
);
Assert.equal(
!!handler.alwaysAskBeforeHandling,
true,
"svg ask should be preserved"
);
// Clean up
HandlerService.remove(handler);
}
// It should still be possible to view XML internally
checkShouldView(XML_MIME, "xml", true);
checkWasRegistered("xml", true);
checkAll(SVG_MIME, "svg", true);
checkAll(WEBP_MIME, "webp", true);
// Disable SVG to test SVG enabled check (depends on the pref)
Services.prefs.setBoolPref(PREF_SVG_DISABLED, true);
// Should have restored the settings from above
{
let handler = MIMEService.getFromTypeAndExtension(SVG_MIME, "svg");
Assert.equal(handler.preferredAction, Ci.nsIHandlerInfo.saveToDisk);
Assert.equal(!!handler.alwaysAskBeforeHandling, true);
// Clean up
HandlerService.remove(handler);
}
checkAll(SVG_MIME, "svg", false);
Services.prefs.setBoolPref(PREF_SVG_DISABLED, false);
checkAll(SVG_MIME, "svg", true);
// Test WebP enabled check (depends on the pref)
Services.prefs.setBoolPref(PREF_WEBP_ENABLED, false);
// Should have restored the settings from above
{
let handler = MIMEService.getFromTypeAndExtension(WEBP_MIME, "webp");
Assert.equal(handler.preferredAction, Ci.nsIHandlerInfo.saveToDisk);
Assert.equal(!!handler.alwaysAskBeforeHandling, false);
// Clean up
HandlerService.remove(handler);
}
checkAll(WEBP_MIME, "webp", false);
Services.prefs.setBoolPref(PREF_WEBP_ENABLED, true);
checkAll(WEBP_MIME, "webp", true);
Assert.ok(!shouldView(null, "pdf"), "missing MIME shouldn't be accepted");
Assert.ok(!shouldView(null, "xml"), "missing MIME shouldn't be accepted");
Assert.ok(!shouldView(OCTET_MIME), "unsupported MIME shouldn't be accepted");
Assert.ok(!shouldView(OCTET_MIME, "exe"), ".exe shouldn't be accepted");
});
registerCleanupFunction(() => {
// Clear all types to remove any saved values
Services.prefs.setCharPref(PREF_ENABLED_TYPES, "");
// Reset to the defaults
Services.prefs.clearUserPref(PREF_ENABLED_TYPES);
Services.prefs.clearUserPref(PREF_SVG_DISABLED);
Services.prefs.clearUserPref(PREF_WEBP_ENABLED);
});

View file

@ -6,4 +6,3 @@ skip-if = toolkit == 'android'
[test_DownloadsCommon_getMimeInfo.js]
[test_DownloadsCommon_isFileOfType.js]
[test_DownloadsViewableInternally.js]

View file

@ -26,15 +26,6 @@ ChromeUtils.defineModuleGetter(
"CloudStorage",
"resource://gre/modules/CloudStorage.jsm"
);
var { Integration } = ChromeUtils.import(
"resource://gre/modules/Integration.jsm"
);
/* global DownloadIntegration */
Integration.downloads.defineModuleGetter(
this,
"DownloadIntegration",
"resource://gre/modules/DownloadIntegration.jsm"
);
ChromeUtils.defineModuleGetter(
this,
"SelectionChangedMenulist",
@ -1958,18 +1949,7 @@ var gMainPane = {
* applications menu.
*/
_loadInternalHandlers() {
let internalHandlers = [new PDFHandlerInfoWrapper()];
let enabledHandlers = Services.prefs
.getCharPref("browser.download.viewableInternally.enabledTypes", "")
.trim();
if (enabledHandlers) {
for (let ext of enabledHandlers.split(",")) {
internalHandlers.push(
new ViewableInternallyHandlerInfoWrapper(ext.trim())
);
}
}
var internalHandlers = [new PDFHandlerInfoWrapper()];
for (let internalHandler of internalHandlers) {
if (internalHandler.enabled) {
this._handledTypes[internalHandler.type] = internalHandler;
@ -2562,7 +2542,7 @@ var gMainPane = {
* Filter the list when the user enters a filter term into the filter field.
*/
filter() {
this._rebuildView(); // FIXME: Should this be await since bug 1508156?
this._rebuildView();
},
focusFilterBox() {
@ -3652,9 +3632,8 @@ class HandlerInfoWrapper {
* menu.
*/
class InternalHandlerInfoWrapper extends HandlerInfoWrapper {
constructor(mimeType, extension) {
let type = gMIMEService.getFromTypeAndExtension(mimeType, extension);
super(mimeType || type.type, type);
constructor(mimeType) {
super(mimeType, gMIMEService.getFromTypeAndExtension(mimeType, null));
}
// Override store so we so we can notify any code listening for registration
@ -3666,24 +3645,22 @@ class InternalHandlerInfoWrapper extends HandlerInfoWrapper {
get enabled() {
throw Components.Exception("", Cr.NS_ERROR_NOT_IMPLEMENTED);
}
get description() {
return { id: this._appPrefLabel };
}
}
class PDFHandlerInfoWrapper extends InternalHandlerInfoWrapper {
constructor() {
super(TYPE_PDF, null);
super(TYPE_PDF);
}
get _appPrefLabel() {
return "applications-type-pdf";
}
get enabled() {
return !Services.prefs.getBoolPref(PREF_PDFJS_DISABLED);
}
}
class ViewableInternallyHandlerInfoWrapper extends InternalHandlerInfoWrapper {
constructor(extension) {
super(null, extension);
}
get enabled() {
return DownloadIntegration.shouldViewDownloadInternally(this.type);
}
}

View file

@ -170,12 +170,9 @@ add_task(async function dialogShowsCorrectContent() {
let desc = dialogWin.document.getElementById("appDescription");
let descL10n = dialogWin.document.l10n.getAttributes(desc);
is(descL10n.id, "app-manager-handle-file", "Should have right string");
let stringBundle = Services.strings.createBundle(
"chrome://mozapps/locale/downloads/unknownContentType.properties"
);
is(
descL10n.args.type,
stringBundle.GetStringFromName("pdfExtHandlerDescription"),
await dialogWin.document.l10n.formatValue("applications-type-pdf"),
"Should have PDF string bits."
);

View file

@ -378,6 +378,11 @@ applications-manage-app =
.label = Application Details…
applications-always-ask =
.label = Always ask
applications-type-pdf = Portable Document Format (PDF)
# Variables:
# $type (String) - the MIME type (e.g application/binary)
applications-type-pdf-with-type = { applications-type-pdf } ({ $type })
# Variables:
# $type-description (String) - Description of the type (e.g "Portable Document Format")

View file

@ -698,21 +698,6 @@ var DownloadIntegration = {
);
},
/**
* Decide whether a download of this type, opened from the downloads
* list, should open internally.
*
* @param aMimeType
* The MIME type of the file, as a string
* @param [optional] aExtension
* The file extension, which can match instead of the MIME type.
*/
shouldViewDownloadInternally(aMimeType, aExtension) {
// Refuse all files by default, this is meant to be replaced with a check
// for specific types via Integration.downloads.register().
return false;
},
/**
* Launches a file represented by the target of a download. This can
* open the file with the default application for the target MIME type
@ -809,6 +794,8 @@ var DownloadIntegration = {
return;
}
const PDF_CONTENT_TYPE = "application/pdf";
if (!useSystemDefault && mimeInfo) {
useSystemDefault = mimeInfo.preferredAction == mimeInfo.useSystemDefault;
}
@ -817,7 +804,8 @@ var DownloadIntegration = {
if (
aDownload.handleInternally ||
(mimeInfo &&
this.shouldViewDownloadInternally(mimeInfo.type, fileExtension) &&
(mimeInfo.type == PDF_CONTENT_TYPE ||
fileExtension?.toLowerCase() == "pdf") &&
!mimeInfo.alwaysAskBeforeHandling &&
mimeInfo.preferredAction === Ci.nsIHandlerInfo.handleInternally &&
!aDownload.launchWhenSucceeded)

View file

@ -16,8 +16,4 @@ unknownCancel.label=Cancel
fileType=%S file
# LOCALIZATION NOTE (orderedFileSizeWithType): first %S is type, second %S is size, and third %S is unit
orderedFileSizeWithType=%1$S (%2$S %3$S)
avifExtHandlerDescription=AV1 Image File (AVIF)
pdfExtHandlerDescription=Portable Document Format (PDF)
svgExtHandlerDescription=Scalable Vector Graphics (SVG)
webpExtHandlerDescription=WebP Image
xmlExtHandlerDescription=Extensible Markup Language (XML)
pdfHandlerDescription=Portable Document Format

View file

@ -22,16 +22,6 @@ XPCOMUtils.defineLazyServiceGetter(
Ci.nsIApplicationReputationService
);
const { Integration } = ChromeUtils.import(
"resource://gre/modules/Integration.jsm"
);
/* global DownloadIntegration */
Integration.downloads.defineModuleGetter(
this,
"DownloadIntegration",
"resource://gre/modules/DownloadIntegration.jsm"
);
// /////////////////////////////////////////////////////////////////////////////
// // Helper Functions
@ -1282,6 +1272,8 @@ nsUnknownContentTypeDialog.prototype = {
},
shouldShowInternalHandlerOption() {
// This is currently available only for PDF files and when
// pdf.js is enabled.
let browsingContext = this.mDialog.BrowsingContext.get(
this.mLauncher.browsingContextId
);
@ -1291,25 +1283,16 @@ nsUnknownContentTypeDialog.prototype = {
// known extensions for this mimetype.
primaryExtension = this.mLauncher.MIMEInfo.primaryExtension;
} catch (e) {}
// Only available for PDF files when pdf.js is enabled.
// Skip if the current window uses the resource scheme, to avoid
// showing the option when using the Download button in pdf.js.
if (primaryExtension == "pdf") {
return (
!browsingContext?.currentWindowGlobal?.documentPrincipal?.URI?.schemeIs(
"resource"
) &&
!Services.prefs.getBoolPref("pdfjs.disabled", true) &&
Services.prefs.getBoolPref(
"browser.helperApps.showOpenOptionForPdfJS",
false
)
);
}
return DownloadIntegration.shouldViewDownloadInternally(
this.mLauncher.MIMEInfo.MIMEType
return (
!browsingContext?.currentWindowGlobal?.documentPrincipal?.URI?.schemeIs(
"resource"
) &&
primaryExtension == "pdf" &&
!Services.prefs.getBoolPref("pdfjs.disabled", true) &&
Services.prefs.getBoolPref(
"browser.helperApps.showOpenOptionForPdfJS",
false
)
);
},

View file

@ -539,16 +539,6 @@ static const nsDefaultMimeTypeEntry nonDecodableExtensions[] = {
{APPLICATION_COMPRESS, "z"},
{APPLICATION_GZIP, "svgz"}};
/**
* Primary extensions of types whose descriptions should be overwritten.
* This extension is concatenated with "ExtHandlerDescription" to look up the
* description in unknownContentType.properties.
* NOTE: These MUST be lower-case and ASCII.
*/
static const char* descriptionOverwriteExtensions[] = {
"avif", "pdf", "svg", "webp", "xml",
};
static StaticRefPtr<nsExternalHelperAppService> sExtHelperAppSvcSingleton;
/**
@ -2576,6 +2566,28 @@ NS_IMETHODIMP nsExternalHelperAppService::GetFromTypeAndExtension(
found = found || NS_SUCCEEDED(rv);
}
// Next, overwrite with generic description if the extension is PDF
// since the file format is supported by Firefox and we don't want
// other brands positioning themselves as the sole viewer for a system.
if (aFileExt.LowerCaseEqualsASCII("pdf") ||
aFileExt.LowerCaseEqualsASCII(".pdf")) {
nsCOMPtr<nsIStringBundleService> bundleService =
do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIStringBundle> unknownContentTypeBundle;
rv = bundleService->CreateBundle(
"chrome://mozapps/locale/downloads/unknownContentType.properties",
getter_AddRefs(unknownContentTypeBundle));
if (NS_SUCCEEDED(rv)) {
nsAutoString pdfHandlerDescription;
rv = unknownContentTypeBundle->GetStringFromName("pdfHandlerDescription",
pdfHandlerDescription);
if (NS_SUCCEEDED(rv)) {
(*_retval)->SetDescription(pdfHandlerDescription);
}
}
}
// Now, let's see if we can find something in our datastore.
// This will not overwrite the OS information that interests us
// (i.e. default application, default app. description)
@ -2645,37 +2657,6 @@ NS_IMETHODIMP nsExternalHelperAppService::GetFromTypeAndExtension(
}
}
// Overwrite with a generic description if the primary extension for the
// type is in our list; these are file formats supported by Firefox and
// we don't want other brands positioning themselves as the sole viewer
// for a system.
nsAutoCString primaryExtension;
rv = (*_retval)->GetPrimaryExtension(primaryExtension);
if (NS_SUCCEEDED(rv)) {
for (const char* ext : descriptionOverwriteExtensions) {
if (primaryExtension.Equals(ext)) {
nsCOMPtr<nsIStringBundleService> bundleService =
do_GetService(NS_STRINGBUNDLE_CONTRACTID, &rv);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<nsIStringBundle> unknownContentTypeBundle;
rv = bundleService->CreateBundle(
"chrome://mozapps/locale/downloads/unknownContentType.properties",
getter_AddRefs(unknownContentTypeBundle));
if (NS_SUCCEEDED(rv)) {
nsAutoCString stringName(ext);
stringName.AppendLiteral("ExtHandlerDescription");
nsAutoString handlerDescription;
rv = unknownContentTypeBundle->GetStringFromName(stringName.get(),
handlerDescription);
if (NS_SUCCEEDED(rv)) {
(*_retval)->SetDescription(handlerDescription);
}
}
break;
}
}
}
if (LOG_ENABLED()) {
nsAutoCString type;
(*_retval)->GetMIMEType(type);

View file

@ -21,8 +21,6 @@ support-files =
file_pdf_binary_octet_stream.pdf^headers^
file_txt_attachment_test.txt
file_txt_attachment_test.txt^headers^
file_xml_attachment_test.xml
file_xml_attachment_test.xml^headers^
[browser_download_urlescape.js]
support-files =
file_with@@funny_name.png

View file

@ -390,44 +390,11 @@ add_task(async function test_check_open_with_external_then_internal() {
}
});
/**
* Check that the "Open with internal handler" option is presented
* for other viewable internally types.
*/
add_task(
async function test_internal_handler_hidden_with_viewable_internally_type() {
let dialogWindowPromise = BrowserTestUtils.domWindowOpenedAndLoaded();
let loadingTab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,
TEST_PATH + "file_xml_attachment_test.xml"
);
let dialogWindow = await dialogWindowPromise;
is(
dialogWindow.location.href,
"chrome://mozapps/content/downloads/unknownContentType.xhtml",
"Should have seen the unknown content dialogWindow."
);
let doc = dialogWindow.document;
let internalHandlerRadio = doc.querySelector("#handleInternally");
// Prevent racing with initialization of the dialog and make sure that
// the final state of the dialog has the correct visibility of the internal-handler option.
await waitForAcceptButtonToGetEnabled(doc);
ok(!internalHandlerRadio.hidden, "The option should be visible for XML");
ok(internalHandlerRadio.selected, "The option should be selected");
let dialog = doc.querySelector("#unknownContentType");
dialog.cancelDialog();
BrowserTestUtils.removeTab(loadingTab);
}
);
/**
* Check that the "Open with internal handler" option is not presented
* for non-PDF, non-viewable-internally types.
* for non-PDF types.
*/
add_task(async function test_internal_handler_hidden_with_other_type() {
add_task(async function test_internal_handler_hidden_with_nonpdf_type() {
let dialogWindowPromise = BrowserTestUtils.domWindowOpenedAndLoaded();
let loadingTab = await BrowserTestUtils.openNewForegroundTab(
gBrowser,

View file

@ -1,4 +0,0 @@
<?xml version = "1.0" encoding = "utf-8"?>
<something>
</something>

View file

@ -1,2 +0,0 @@
Content-Disposition: attachment; filename=file_xml_attachment_test.xml
Content-Type: text/xml