author | Gijs Kruitbosch <gijskruitbosch@gmail.com> |
Thu, 23 Jan 2020 08:36:00 +0000 | |
changeset 511323 | af1b9cf9eec60af9cebc46a90b393f1ef8313d43 |
parent 511322 | 2840946503b2b78ee175d121371991a3ef234df2 |
child 511324 | 169c76460aa48f861d4c8f916d3aacdd40238f1a |
push id | 37048 |
push user | rmaries@mozilla.com |
push date | Thu, 23 Jan 2020 21:42:24 +0000 |
treeherder | mozilla-central@fb6b61e49217 [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | smaug, johannh |
bugs | 1526731 |
milestone | 74.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/browser/actors/ContextMenuChild.jsm +++ b/browser/actors/ContextMenuChild.jsm @@ -218,16 +218,18 @@ class ContextMenuChild extends JSWindowA "canvas" ); canvas.width = video.videoWidth; canvas.height = video.videoHeight; let ctxDraw = canvas.getContext("2d"); ctxDraw.drawImage(video, 0, 0); + // Note: if changing the content type, don't forget to update + // consumers that also hardcode this content type. return Promise.resolve(canvas.toDataURL("image/jpeg", "")); } case "ContextMenu:SetAsDesktopBackground": { let target = ContentDOMReference.resolve(message.data.targetIdentifier); // Paranoia: check disableSetDesktopBackground again, in case the // image changed since the context menu was initiated.
--- a/browser/base/content/nsContextMenu.js +++ b/browser/base/content/nsContextMenu.js @@ -1280,17 +1280,17 @@ class nsContextMenu { saveImageURL( dataURL, name, "SaveImageTitle", true, // bypass cache false, // don't skip prompt for where to save referrerInfo, // referrer info null, // document - null, // content type + "image/jpeg", // content type - keep in sync with ContextMenuChild! null, // content disposition isPrivate, this.principal ); }); } leaveDOMFullScreen() { @@ -1588,17 +1588,17 @@ class nsContextMenu { saveImageURL( blobURL, "canvas.png", "SaveImageTitle", true, false, referrerInfo, null, - null, + "image/png", // _canvasToBlobURL uses image/png by default. null, isPrivate, document.nodePrincipal /* system, because blob: */ ); }, Cu.reportError); } else if (this.onImage) { urlSecurityCheck(this.mediaURL, this.principal); saveImageURL(
--- a/browser/components/shell/nsMacShellService.cpp +++ b/browser/components/shell/nsMacShellService.cpp @@ -148,17 +148,18 @@ nsMacShellService::SetDesktopBackground( if (docShell) { loadContext = do_QueryInterface(docShell); } nsCOMPtr<nsIReferrerInfo> referrerInfo = new mozilla::dom::ReferrerInfo(); referrerInfo->InitWithNode(aElement); return wbp->SaveURI(imageURI, aElement->NodePrincipal(), 0, referrerInfo, - nullptr, nullptr, mBackgroundFile, loadContext); + nullptr, nullptr, mBackgroundFile, + nsIContentPolicy::TYPE_IMAGE, loadContext); } NS_IMETHODIMP nsMacShellService::OnProgressChange(nsIWebProgress* aWebProgress, nsIRequest* aRequest, int32_t aCurSelfProgress, int32_t aMaxSelfProgress, int32_t aCurTotalProgress,
--- a/dom/base/nsContentAreaDragDrop.cpp +++ b/dom/base/nsContentAreaDragDrop.cpp @@ -23,16 +23,17 @@ #include "nsISupportsPrimitives.h" #include "nsServiceManagerUtils.h" #include "nsNetUtil.h" #include "nsIFile.h" #include "nsFrameLoader.h" #include "nsFrameLoaderOwner.h" #include "nsIContent.h" #include "nsIContentInlines.h" +#include "nsIContentPolicy.h" #include "nsIImageLoadingContent.h" #include "nsUnicharUtils.h" #include "nsIURL.h" #include "nsIURIMutator.h" #include "mozilla/dom/Document.h" #include "nsIPrincipal.h" #include "nsIWebBrowserPersist.h" #include "nsEscape.h" @@ -122,17 +123,18 @@ nsresult nsContentAreaDragDrop::GetDragD NS_IMPL_ISUPPORTS(nsContentAreaDragDropDataProvider, nsIFlavorDataProvider) // SaveURIToFile // used on platforms where it's possible to drag items (e.g. images) // into the file system nsresult nsContentAreaDragDropDataProvider::SaveURIToFile( nsIURI* inSourceURI, nsIPrincipal* inTriggeringPrincipal, - nsIFile* inDestFile, bool isPrivate) { + nsIFile* inDestFile, nsContentPolicyType inContentPolicyType, + bool isPrivate) { nsCOMPtr<nsIURL> sourceURL = do_QueryInterface(inSourceURI); if (!sourceURL) { return NS_ERROR_NO_INTERFACE; } nsresult rv = inDestFile->CreateUnique(nsIFile::NORMAL_FILE_TYPE, 0600); NS_ENSURE_SUCCESS(rv, rv); @@ -143,17 +145,17 @@ nsresult nsContentAreaDragDropDataProvid NS_ENSURE_SUCCESS(rv, rv); persist->SetPersistFlags( nsIWebBrowserPersist::PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION); // referrer policy can be anything since the referrer is nullptr return persist->SavePrivacyAwareURI(inSourceURI, inTriggeringPrincipal, 0, nullptr, nullptr, nullptr, inDestFile, - isPrivate); + inContentPolicyType, isPrivate); } /* * Check if the provided filename extension is valid for the MIME type and * return the MIME type's primary extension. * * @param aExtension [in] the extension to check * @param aMimeType [in] the MIME type to check the extension with @@ -308,17 +310,20 @@ nsContentAreaDragDropDataProvider::GetFl rv = destDirectory->Clone(getter_AddRefs(file)); NS_ENSURE_SUCCESS(rv, rv); file->Append(targetFilename); bool isPrivate = aTransferable->GetIsPrivateData(); nsCOMPtr<nsIPrincipal> principal = aTransferable->GetRequestingPrincipal(); - rv = SaveURIToFile(sourceURI, principal, file, isPrivate); + nsContentPolicyType contentPolicyType = + aTransferable->GetContentPolicyType(); + rv = + SaveURIToFile(sourceURI, principal, file, contentPolicyType, isPrivate); // send back an nsIFile if (NS_SUCCEEDED(rv)) { CallQueryInterface(file, aData); } } return rv; }
--- a/dom/base/nsContentAreaDragDrop.h +++ b/dom/base/nsContentAreaDragDrop.h @@ -68,12 +68,13 @@ class nsContentAreaDragDropDataProvider virtual ~nsContentAreaDragDropDataProvider() {} public: NS_DECL_ISUPPORTS NS_DECL_NSIFLAVORDATAPROVIDER nsresult SaveURIToFile(nsIURI* inSourceURI, nsIPrincipal* inTriggeringPrincipal, - nsIFile* inDestFile, bool isPrivate); + nsIFile* inDestFile, nsContentPolicyType inPolicyType, + bool isPrivate); }; #endif /* nsContentAreaDragDrop_h__ */
--- a/dom/tests/browser/browser.ini +++ b/dom/tests/browser/browser.ini @@ -67,16 +67,17 @@ fail-if = fission skip-if = !e10s || # This is a test of e10s functionality. (fission && debug) # Intermittently fails uncleanly and breaks subsequent tests. [browser_persist_cookies.js] support-files = set-samesite-cookies-and-redirect.sjs mimeme.sjs skip-if = fission +[browser_persist_image_accept.js] [browser_persist_mixed_content_image.js] support-files = test_mixed_content_image.html dummy.png [browser_pointerlock_warning.js] [browser_test_focus_after_modal_state.js] skip-if = verify support-files =
new file mode 100644 --- /dev/null +++ b/dom/tests/browser/browser_persist_image_accept.js @@ -0,0 +1,128 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const TEST_PATH = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "https://example.org" +); + +var MockFilePicker = SpecialPowers.MockFilePicker; +MockFilePicker.init(window); + +registerCleanupFunction(async function() { + info("Running the cleanup code"); + MockFilePicker.cleanup(); + if (gTestDir && gTestDir.exists()) { + // On Windows, sometimes nsIFile.remove() throws, probably because we're + // still writing to the directory we're trying to remove, despite + // waiting for the download to complete. Just retry a bit later... + let succeeded = false; + while (!succeeded) { + try { + gTestDir.remove(true); + succeeded = true; + } catch (ex) { + await new Promise(requestAnimationFrame); + } + } + } +}); + +let gTestDir = null; + +function createTemporarySaveDirectory() { + var saveDir = Services.dirsvc.get("TmpD", Ci.nsIFile); + saveDir.append("testsavedir"); + if (!saveDir.exists()) { + info("create testsavedir!"); + saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755); + } + info("return from createTempSaveDir: " + saveDir.path); + return saveDir; +} + +add_task(async function test_image_download() { + await BrowserTestUtils.withNewTab(TEST_PATH + "dummy.html", async browser => { + // Add the image, and wait for it to load. + await SpecialPowers.spawn(browser, [], async function() { + let loc = content.document.location.href; + let imgloc = new content.URL("dummy.png", loc); + let img = content.document.createElement("img"); + img.src = imgloc; + await new Promise(resolve => { + img.onload = resolve; + content.document.body.appendChild(img); + }); + }); + gTestDir = createTemporarySaveDirectory(); + + let destFile = gTestDir.clone(); + + MockFilePicker.displayDirectory = gTestDir; + let fileName; + MockFilePicker.showCallback = function(fp) { + info("showCallback"); + fileName = fp.defaultString; + info("fileName: " + fileName); + destFile.append(fileName); + info("path: " + destFile.path); + MockFilePicker.setFiles([destFile]); + MockFilePicker.filterIndex = 0; // just save the file + info("done showCallback"); + }; + let publicDownloads = await Downloads.getList(Downloads.PUBLIC); + let downloadFinishedPromise = new Promise(resolve => { + publicDownloads.addView({ + onDownloadChanged(download) { + info("Download changed!"); + if (download.succeeded || download.error) { + info("Download succeeded or errored"); + publicDownloads.removeView(this); + publicDownloads.removeFinished(); + resolve(download); + } + }, + }); + }); + let httpOnModifyPromise = TestUtils.topicObserved( + "http-on-modify-request", + (s, t, d) => { + let channel = s.QueryInterface(Ci.nsIChannel); + let uri = channel.URI && channel.URI.spec; + if (!uri.endsWith("dummy.png")) { + info("Ignoring request for " + uri); + return false; + } + ok(channel instanceof Ci.nsIHttpChannel, "Should be HTTP channel"); + channel.QueryInterface(Ci.nsIHttpChannel); + is( + channel.getRequestHeader("Accept"), + Services.prefs.getCharPref("image.http.accept"), + "Header should be image header" + ); + return true; + } + ); + // open the context menu. + let popup = document.getElementById("contentAreaContextMenu"); + let popupShown = BrowserTestUtils.waitForEvent(popup, "popupshown"); + BrowserTestUtils.synthesizeMouseAtCenter( + "img", + { type: "contextmenu", button: 2 }, + browser + ); + await popupShown; + let popupHidden = BrowserTestUtils.waitForEvent(popup, "popuphidden"); + popup.querySelector("#context-saveimage").click(); + popup.hidePopup(); + await popupHidden; + info("Context menu hidden, waiting for download to finish"); + let imageDownload = await downloadFinishedPromise; + ok(imageDownload.succeeded, "Image should have downloaded successfully"); + info("Waiting for http request to complete."); + // Ensure we got the http request: + await httpOnModifyPromise; + }); +});
--- a/dom/tests/browser/browser_persist_mixed_content_image.js +++ b/dom/tests/browser/browser_persist_mixed_content_image.js @@ -70,25 +70,25 @@ add_task(async function test_image_downl fileName = fp.defaultString; info("fileName: " + fileName); destFile.append(fileName); info("path: " + destFile.path); MockFilePicker.setFiles([destFile]); MockFilePicker.filterIndex = 0; // just save the file info("done showCallback"); }; - let downloadFinishedPromise = new Promise(async resolve => { - let dls = await Downloads.getList(Downloads.PUBLIC); - dls.addView({ + let publicDownloads = await Downloads.getList(Downloads.PUBLIC); + let downloadFinishedPromise = new Promise(resolve => { + publicDownloads.addView({ onDownloadChanged(download) { info("Download changed!"); if (download.succeeded || download.error) { info("Download succeeded or errored"); - dls.removeView(this); - dls.removeFinished(); + publicDownloads.removeView(this); + publicDownloads.removeFinished(); resolve(download); } }, }); }); // open the context menu. let popup = document.getElementById("contentAreaContextMenu"); let popupShown = BrowserTestUtils.waitForEvent(popup, "popupshown");
--- a/dom/webbrowserpersist/nsIWebBrowserPersist.idl +++ b/dom/webbrowserpersist/nsIWebBrowserPersist.idl @@ -1,15 +1,16 @@ /* -*- Mode: IDL; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- * * 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/. */ #include "nsICancelable.idl" +#include "nsIContentPolicy.idl" interface nsIURI; interface nsIInputStream; interface nsIWebProgressListener; interface nsIFile; interface nsIChannel; interface nsILoadContext; interface nsIPrincipal; @@ -119,16 +120,17 @@ interface nsIWebBrowserPersist : nsICanc * HTTP Referer header. * @param aPostData Post data to pass with an HTTP request or * <CODE>nullptr</CODE>. * @param aExtraHeaders Additional headers to supply with an HTTP request * or <CODE>nullptr</CODE>. * @param aFile Target file. This may be a nsIFile object or an * nsIURI object with a file scheme or a scheme that * supports uploading (e.g. ftp). + * @param aContentPolicyType The type of content we're saving. * @param aPrivacyContext A context from which the privacy status of this * save operation can be determined. Must only be null * in situations in which no such context is available * (eg. the operation has no logical association with any * window or document) * * @see nsIFile * @see nsIURI @@ -136,29 +138,31 @@ interface nsIWebBrowserPersist : nsICanc * * @throws NS_ERROR_INVALID_ARG One or more arguments was invalid. */ void saveURI(in nsIURI aURI, in nsIPrincipal aTriggeringPrincipal, in unsigned long aCacheKey, in nsIReferrerInfo aReferrerInfo, in nsIInputStream aPostData, in string aExtraHeaders, in nsISupports aFile, + in nsContentPolicyType aContentPolicyType, in nsILoadContext aPrivacyContext); /** * @param aIsPrivate Treat the save operation as private (ie. with * regards to networking operations and persistence * of intermediate data, etc.) * @see saveURI for all other parameter descriptions */ void savePrivacyAwareURI(in nsIURI aURI, in nsIPrincipal aTriggeringPrincipal, in unsigned long aCacheKey, in nsIReferrerInfo aReferrerInfo, in nsIInputStream aPostData, in string aExtraHeaders, in nsISupports aFile, + in nsContentPolicyType aContentPolicyType, in boolean aIsPrivate); /** * Save a channel to a file. It must not be opened yet. * @see saveURI */ void saveChannel(in nsIChannel aChannel, in nsISupports aFile);
--- a/dom/webbrowserpersist/nsWebBrowserPersist.cpp +++ b/dom/webbrowserpersist/nsWebBrowserPersist.cpp @@ -354,39 +354,41 @@ NS_IMETHODIMP nsWebBrowserPersist::SetPr mEventSink = do_GetInterface(aProgressListener); return NS_OK; } NS_IMETHODIMP nsWebBrowserPersist::SaveURI( nsIURI* aURI, nsIPrincipal* aPrincipal, uint32_t aCacheKey, nsIReferrerInfo* aReferrerInfo, nsIInputStream* aPostData, const char* aExtraHeaders, nsISupports* aFile, - nsILoadContext* aPrivacyContext) { + nsContentPolicyType aContentPolicyType, nsILoadContext* aPrivacyContext) { bool isPrivate = aPrivacyContext && aPrivacyContext->UsePrivateBrowsing(); return SavePrivacyAwareURI(aURI, aPrincipal, aCacheKey, aReferrerInfo, - aPostData, aExtraHeaders, aFile, isPrivate); + aPostData, aExtraHeaders, aFile, + aContentPolicyType, isPrivate); } NS_IMETHODIMP nsWebBrowserPersist::SavePrivacyAwareURI( nsIURI* aURI, nsIPrincipal* aPrincipal, uint32_t aCacheKey, nsIReferrerInfo* aReferrerInfo, nsIInputStream* aPostData, - const char* aExtraHeaders, nsISupports* aFile, bool aIsPrivate) { + const char* aExtraHeaders, nsISupports* aFile, + nsContentPolicyType aContentPolicy, bool aIsPrivate) { NS_ENSURE_TRUE(mFirstAndOnlyUse, NS_ERROR_FAILURE); mFirstAndOnlyUse = false; // Stop people from reusing this object! nsCOMPtr<nsIURI> fileAsURI; nsresult rv; rv = GetValidURIFromObject(aFile, getter_AddRefs(fileAsURI)); NS_ENSURE_SUCCESS(rv, NS_ERROR_INVALID_ARG); // SaveURI doesn't like broken uris. mPersistFlags |= PERSIST_FLAGS_FAIL_ON_BROKEN_LINKS; - rv = SaveURIInternal(aURI, aPrincipal, nsIContentPolicy::TYPE_SAVEAS_DOWNLOAD, - aCacheKey, aReferrerInfo, aPostData, aExtraHeaders, - fileAsURI, false, aIsPrivate); + rv = SaveURIInternal(aURI, aPrincipal, aContentPolicy, aCacheKey, + aReferrerInfo, aPostData, aExtraHeaders, fileAsURI, + false, aIsPrivate); return NS_FAILED(rv) ? rv : NS_OK; } NS_IMETHODIMP nsWebBrowserPersist::SaveChannel(nsIChannel* aChannel, nsISupports* aFile) { NS_ENSURE_TRUE(mFirstAndOnlyUse, NS_ERROR_FAILURE); mFirstAndOnlyUse = false; // Stop people from reusing this object!
--- a/toolkit/components/browser/nsWebBrowser.cpp +++ b/toolkit/components/browser/nsWebBrowser.cpp @@ -728,28 +728,32 @@ nsWebBrowser::SetProgressListener(nsIWeb mProgressListener = aProgressListener; return NS_OK; } NS_IMETHODIMP nsWebBrowser::SaveURI(nsIURI* aURI, nsIPrincipal* aPrincipal, uint32_t aCacheKey, nsIReferrerInfo* aReferrerInfo, nsIInputStream* aPostData, const char* aExtraHeaders, - nsISupports* aFile, nsILoadContext* aPrivacyContext) { + nsISupports* aFile, + nsContentPolicyType aContentPolicyType, + nsILoadContext* aPrivacyContext) { return SavePrivacyAwareURI( aURI, aPrincipal, aCacheKey, aReferrerInfo, aPostData, aExtraHeaders, - aFile, aPrivacyContext && aPrivacyContext->UsePrivateBrowsing()); + aFile, aContentPolicyType, + aPrivacyContext && aPrivacyContext->UsePrivateBrowsing()); } NS_IMETHODIMP nsWebBrowser::SavePrivacyAwareURI(nsIURI* aURI, nsIPrincipal* aPrincipal, uint32_t aCacheKey, nsIReferrerInfo* aReferrerInfo, nsIInputStream* aPostData, const char* aExtraHeaders, nsISupports* aFile, + nsContentPolicyType aContentPolicyType, bool aIsPrivate) { if (mPersist) { uint32_t currentState; mPersist->GetCurrentState(¤tState); if (currentState == PERSIST_STATE_FINISHED) { mPersist = nullptr; } else { // You can't save again until the last save has completed @@ -772,17 +776,17 @@ nsWebBrowser::SavePrivacyAwareURI(nsIURI mPersist = do_CreateInstance(NS_WEBBROWSERPERSIST_CONTRACTID, &rv); NS_ENSURE_SUCCESS(rv, rv); mPersist->SetProgressListener(this); mPersist->SetPersistFlags(mPersistFlags); mPersist->GetCurrentState(&mPersistCurrentState); rv = mPersist->SavePrivacyAwareURI(uri, aPrincipal, aCacheKey, aReferrerInfo, aPostData, aExtraHeaders, aFile, - aIsPrivate); + aContentPolicyType, aIsPrivate); if (NS_FAILED(rv)) { mPersist = nullptr; } return rv; } NS_IMETHODIMP nsWebBrowser::SaveChannel(nsIChannel* aChannel, nsISupports* aFile) {
--- a/toolkit/components/downloads/test/unit/head.js +++ b/toolkit/components/downloads/test/unit/head.js @@ -415,16 +415,17 @@ function promiseStartLegacyDownload(aSou persist.savePrivacyAwareURI( sourceURI, Services.scriptSecurityManager.getSystemPrincipal(), 0, referrerInfo, null, null, targetFile, + Ci.nsIContentPolicy.TYPE_SAVEAS_DOWNLOAD, isPrivate ); }) .catch(do_report_unexpected_exception); }); } /**
--- a/toolkit/components/viewsource/content/viewSourceUtils.js +++ b/toolkit/components/viewsource/content/viewSourceUtils.js @@ -249,16 +249,17 @@ var gViewSourceUtils = { webBrowserPersist.savePrivacyAwareURI( uri, principal, null, null, null, null, file, + Ci.nsIContentPolicy.TYPE_SAVEAS_DOWNLOAD, data.isPrivate ); let helperService = Cc[ "@mozilla.org/uriloader/external-helper-app-service;1" ].getService(Ci.nsPIExternalAppLauncher); if (data.isPrivate) { // register the file to be deleted when possible
--- a/toolkit/content/contentAreaUtils.js +++ b/toolkit/content/contentAreaUtils.js @@ -461,16 +461,17 @@ function internalSave( if (aCacheKey == undefined) { aCacheKey = 0; } // Note: aDocument == null when this code is used by save-link-as... var saveMode = GetSaveModeForContentType(aContentType, aDocument); var file, sourceURI, saveAsType; + let contentPolicyType = Ci.nsIContentPolicy.TYPE_SAVEAS_DOWNLOAD; // Find the URI object for aURL and the FileName/Extension to use when saving. // FileName/Extension will be ignored if aChosenData supplied. if (aChosenData) { file = aChosenData.file; sourceURI = aChosenData.uri; saveAsType = kSaveAsType_Complete; continueSave(); @@ -485,16 +486,19 @@ function internalSave( aURL, charset, aDocument, aContentType, aContentDisposition ); sourceURI = fileInfo.uri; + if (aContentType && aContentType.startsWith("image/")) { + contentPolicyType = Ci.nsIContentPolicy.TYPE_IMAGE; + } var fpParams = { fpTitleKey: aFilePickerTitleKey, fileInfo, contentType: aContentType, saveMode, saveAsType: kSaveAsType_Complete, file, }; @@ -553,16 +557,17 @@ function internalSave( sourcePrincipal, sourceReferrerInfo: aReferrerInfo, sourceDocument: useSaveDocument ? aDocument : null, targetContentType: saveAsType == kSaveAsType_Text ? "text/plain" : null, targetFile: file, sourceCacheKey: aCacheKey, sourcePostData: nonCPOWDocument ? getPostData(aDocument) : null, bypassCache: aShouldBypassCache, + contentPolicyType, isPrivate, }; // Start the actual save process internalPersist(persistArgs); } } @@ -581,16 +586,19 @@ function internalSave( * the nsIReferrerInfo of the referrer info to use, or null if no * referrer should be sent. * @param persistArgs.sourcePostData * Required and used only when persistArgs.sourceDocument is NOT present, * represents the POST data to be sent along with the HTTP request, and * must be null if no POST data should be sent. * @param persistArgs.targetFile * The nsIFile of the file to create + * @param persistArgs.contentPolicyType + * The type of content we're saving. Will be used to determine what + * content is accepted, enforce sniffing restrictions, etc. * @param persistArgs.targetContentType * Required and used only when persistArgs.sourceDocument is present, * determines the final content type of the saved file, or null to use * the same content type as the source document. Currently only * "text/plain" is meaningful. * @param persistArgs.bypassCache * If true, the document will always be refetched from the server * @param persistArgs.isPrivate @@ -666,16 +674,17 @@ function internalPersist(persistArgs) { persist.savePrivacyAwareURI( persistArgs.sourceURI, persistArgs.sourcePrincipal, persistArgs.sourceCacheKey, persistArgs.sourceReferrerInfo, persistArgs.sourcePostData, null, targetFileURL, + persistArgs.contentPolicyType || Ci.nsIContentPolicy.TYPE_SAVEAS_DOWNLOAD, persistArgs.isPrivate ); } } /** * Structure for holding info about automatically supplied parameters for * internalSave(...). This allows parameters to be supplied so the user does not
--- a/toolkit/content/tests/browser/browser_saveImageURL.js +++ b/toolkit/content/tests/browser/browser_saveImageURL.js @@ -43,17 +43,17 @@ add_task(async function preferred_API() saveImageURL( url, "image.jpg", null, true, false, null, null, - null, + "image/jpeg", null, false, gBrowser.contentPrincipal ); await SpecialPowers.spawn(gBrowser.selectedBrowser, [], async () => { let channel = docShell.currentDocumentChannel; if (channel) { todo( @@ -109,13 +109,23 @@ add_task(async function deprecated_API() // 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, null, null); + saveImageURL( + url, + "image.jpg", + null, + true, + false, + null, + doc, + "image/jpeg", + null + ); await filePickerPromise; } ); });