Bug 1616881 - remove saveImageURL which, besides the now-dead CPOW checks, just calls internalSave, r=mconley

Differential Revision: https://phabricator.services.mozilla.com/D70684
This commit is contained in:
Gijs Kruitbosch
2020-04-13 17:43:22 +00:00
parent b99b3dba92
commit fea0bda34d
3 changed files with 43 additions and 213 deletions

View File

@@ -1302,16 +1302,19 @@ class nsContextMenu {
this.actor.saveVideoFrameAsImage(this.targetIdentifier).then(dataURL => { this.actor.saveVideoFrameAsImage(this.targetIdentifier).then(dataURL => {
// FIXME can we switch this to a blob URL? // FIXME can we switch this to a blob URL?
saveImageURL( internalSave(
dataURL, dataURL,
name,
"SaveImageTitle",
true, // bypass cache
false, // don't skip prompt for where to save
referrerInfo, // referrer info
null, // document null, // document
"image/jpeg", // content type - keep in sync with ContextMenuChild! name,
null, // content disposition null, // content disposition
"image/jpeg", // content type - keep in sync with ContextMenuChild!
true, // bypass cache
"SaveImageTitle",
null, // chosen data
referrerInfo,
null, // initiating doc
false, // don't skip prompt for where to save
null, // cache key
isPrivate, isPrivate,
this.principal this.principal
); );
@@ -1610,32 +1613,38 @@ class nsContextMenu {
if (this.onCanvas) { if (this.onCanvas) {
// Bypass cache, since it's a data: URL. // Bypass cache, since it's a data: URL.
this._canvasToBlobURL(this.targetIdentifier).then(function(blobURL) { this._canvasToBlobURL(this.targetIdentifier).then(function(blobURL) {
saveImageURL( internalSave(
blobURL, blobURL,
null, // document
"canvas.png", "canvas.png",
"SaveImageTitle", null, // content disposition
true,
false,
referrerInfo,
null,
"image/png", // _canvasToBlobURL uses image/png by default. "image/png", // _canvasToBlobURL uses image/png by default.
null, true, // bypass cache
"SaveImageTitle",
null, // chosen data
referrerInfo,
null, // initiating doc
false, // don't skip prompt for where to save
null, // cache key
isPrivate, isPrivate,
document.nodePrincipal /* system, because blob: */ document.nodePrincipal /* system, because blob: */
); );
}, Cu.reportError); }, Cu.reportError);
} else if (this.onImage) { } else if (this.onImage) {
urlSecurityCheck(this.mediaURL, this.principal); urlSecurityCheck(this.mediaURL, this.principal);
saveImageURL( internalSave(
this.mediaURL, this.mediaURL,
null, null, // document
"SaveImageTitle", null, // file name; we'll take it from the URL
false,
false,
referrerInfo,
null,
this.contentData.contentType,
this.contentData.contentDisposition, this.contentData.contentDisposition,
this.contentData.contentType,
false, // do not bypass the cache
"SaveImageTitle",
null, // chosen data
referrerInfo,
null, // initiating doc
false, // don't skip prompt for where to save
null, // cache key
isPrivate, isPrivate,
this.principal this.principal
); );

View File

@@ -96,129 +96,6 @@ function saveURL(
); );
} }
// Just like saveURL, but will get some info off the image before
// calling internalSave
// Clientele: (Make sure you don't break any of these)
// - Context -> Save Image As...
const imgICache = Ci.imgICache;
const nsISupportsCString = Ci.nsISupportsCString;
/**
* Offers to save an image URL to the file system.
*
* @param aURL (string)
* The URL of the image to be saved.
* @param aFileName (string)
* The suggested filename for the saved file.
* @param aFilePickerTitleKey (string, optional)
* Localized string key for an alternate title for the file
* picker. If set to null, this will default to something sensible.
* @param aShouldBypassCache (bool)
* If true, the image will always be retrieved from the server instead
* of the network or image caches.
* @param aSkipPrompt (bool)
* If true, we will attempt to save the file with the suggested
* filename to the default downloads folder without showing the
* file picker.
* @param aReferrerInfo (nsIReferrerInfo, optional)
* the referrerInfo object to use, or null if no referrer should be sent.
* @param aDoc (Document, deprecated, optional)
* The content document that the save is being initiated from. If this
* is omitted, then aIsContentWindowPrivate must be provided.
* @param aContentType (string, optional)
* The content type of the image.
* @param aContentDisp (string, optional)
* The content disposition of the image.
* @param aIsContentWindowPrivate (bool)
* Whether or not the containing window is in private browsing mode.
* Does not need to be provided is aDoc is passed.
*/
function saveImageURL(
aURL,
aFileName,
aFilePickerTitleKey,
aShouldBypassCache,
aSkipPrompt,
aReferrerInfo,
aDoc,
aContentType,
aContentDisp,
aIsContentWindowPrivate,
aPrincipal
) {
forbidCPOW(aURL, "saveImageURL", "aURL");
forbidCPOW(aReferrerInfo, "saveImageURL", "aReferrerInfo");
if (aDoc && aIsContentWindowPrivate == undefined) {
if (Cu.isCrossProcessWrapper(aDoc)) {
Deprecated.warning(
"saveImageURL should not be passed document CPOWs. " +
"The caller should pass in the content type and " +
"disposition themselves",
"https://bugzilla.mozilla.org/show_bug.cgi?id=1243643"
);
}
// This will definitely not work for in-browser code or multi-process compatible
// add-ons due to bug 1233497, which makes unsafe CPOW usage throw by default.
Deprecated.warning(
"saveImageURL should be passed the private state of " +
"the containing window.",
"https://bugzilla.mozilla.org/show_bug.cgi?id=1243643"
);
aIsContentWindowPrivate = PrivateBrowsingUtils.isContentWindowPrivate(
aDoc.defaultView
);
}
// We'd better have the private state by now.
if (aIsContentWindowPrivate == undefined) {
throw new Error(
"saveImageURL couldn't compute private state of content window"
);
}
if (
!aShouldBypassCache &&
aDoc &&
!Cu.isCrossProcessWrapper(aDoc) &&
!aContentType &&
!aContentDisp
) {
try {
var imageCache = Cc["@mozilla.org/image/tools;1"]
.getService(Ci.imgITools)
.getImgCacheForDocument(aDoc);
var props = imageCache.findEntryProperties(
makeURI(aURL, getCharsetforSave(null)),
aDoc
);
if (props) {
aContentType = props.get("type", nsISupportsCString);
aContentDisp = props.get("content-disposition", nsISupportsCString);
}
} catch (e) {
// Failure to get type and content-disposition off the image is non-fatal
}
}
internalSave(
aURL,
null,
aFileName,
aContentDisp,
aContentType,
aShouldBypassCache,
aFilePickerTitleKey,
null,
aReferrerInfo,
aDoc,
aSkipPrompt,
null,
aIsContentWindowPrivate,
aPrincipal
);
}
// This is like saveDocument, but takes any browser/frame-like element // This is like saveDocument, but takes any browser/frame-like element
// and saves the current document inside it, // and saves the current document inside it,
// whether in-process or out-of-process. // whether in-process or out-of-process.

View File

@@ -2,7 +2,6 @@
const IMAGE_PAGE = const IMAGE_PAGE =
"https://example.com/browser/toolkit/content/tests/browser/image_page.html"; "https://example.com/browser/toolkit/content/tests/browser/image_page.html";
const PREF_UNSAFE_FORBIDDEN = "dom.ipc.cpows.forbid-unsafe-from-browser";
var MockFilePicker = SpecialPowers.MockFilePicker; var MockFilePicker = SpecialPowers.MockFilePicker;
@@ -24,8 +23,7 @@ function waitForFilePicker() {
} }
/** /**
* Test that saveImageURL works when we pass in the aIsContentWindowPrivate * Test that internalSave works when saving an image like the context menu does.
* argument instead of a document. This is the preferred API.
*/ */
add_task(async function preferred_API() { add_task(async function preferred_API() {
await BrowserTestUtils.withNewTab( await BrowserTestUtils.withNewTab(
@@ -40,17 +38,20 @@ add_task(async function preferred_API() {
}); });
let filePickerPromise = waitForFilePicker(); let filePickerPromise = waitForFilePicker();
saveImageURL( internalSave(
url, url,
null, // document
"image.jpg", "image.jpg",
null, null, // content disposition
true,
false,
null,
null,
"image/jpeg", "image/jpeg",
null, true, // bypass cache
false, null, // dialog title key
null, // chosen data
null, // no referrer info
null, // no document
false, // don't skip the filename prompt
null, // cache key
false, // not private.
gBrowser.contentPrincipal gBrowser.contentPrincipal
); );
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async () => { await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async () => {
@@ -72,60 +73,3 @@ add_task(async function preferred_API() {
} }
); );
}); });
/**
* Test that saveImageURL will still work when passed a document instead
* of the aIsContentWindowPrivate argument. This is the deprecated API, and
* will not work in apps using remote browsers having PREF_UNSAFE_FORBIDDEN
* set to true.
*/
add_task(async function deprecated_API() {
await BrowserTestUtils.withNewTab(
{
gBrowser,
url: IMAGE_PAGE,
},
async function(browser) {
await pushPrefs([PREF_UNSAFE_FORBIDDEN, false]);
let url = await SpecialPowers.spawn(browser, [], async function() {
let image = content.document.getElementById("image");
return image.href;
});
// Now get the document directly from content. If we run this test with
// e10s-enabled, this will be a CPOW, which is forbidden. We'll just
// pass the XUL document instead to test this interface.
let doc = document;
await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async () => {
let channel = docShell.currentDocumentChannel;
if (channel) {
todo(
channel.QueryInterface(Ci.nsIHttpChannelInternal)
.channelIsForDownload
);
// Throttleable is the only class flag assigned to downloads.
todo(
channel.QueryInterface(Ci.nsIClassOfService).classFlags ==
Ci.nsIClassOfService.Throttleable
);
}
});
let filePickerPromise = waitForFilePicker();
saveImageURL(
url,
"image.jpg",
null,
true,
false,
null,
doc,
"image/jpeg",
null
);
await filePickerPromise;
}
);
});