This is an automated email from the git hooks/post-receive script.
richard pushed a commit to branch base-browser-102.5.0esr-12.0-1 in repository tor-browser.
commit 2bf1348368a4b40e70c14a59f420ef5780597ee5 Author: Neil Deakin neil@mozilla.com AuthorDate: Wed Oct 19 12:50:16 2022 +0000
Bug 1778597, append valid extensions only when saving a page, r=Gijs,necko-reviewers, a=dmeehan
Differential Revision: https://phabricator.services.mozilla.com/D159478 --- netwerk/mime/nsIMIMEService.idl | 10 +++++++ toolkit/content/contentAreaUtils.js | 2 +- .../exthandler/nsExternalHelperAppService.cpp | 8 +++-- uriloader/exthandler/nsExternalHelperAppService.h | 1 + .../tests/mochitest/browser_save_filenames.js | 35 +++++++++++++++++++++- .../exthandler/tests/mochitest/save_filenames.html | 11 ++++--- 6 files changed, 58 insertions(+), 9 deletions(-)
diff --git a/netwerk/mime/nsIMIMEService.idl b/netwerk/mime/nsIMIMEService.idl index c5d1efbd7575..2931ea0cdc51 100644 --- a/netwerk/mime/nsIMIMEService.idl +++ b/netwerk/mime/nsIMIMEService.idl @@ -149,6 +149,16 @@ interface nsIMIMEService : nsISupports { */ const long VALIDATE_NO_DEFAULT_FILENAME = 32;
+ /** + * When the filename has an invalid extension, force the the filename to + * have a valid extension appended to the end of the filename when that + * extension would normally be ignored for the given content type. This + * primarily is used when saving pages to ensure that the html extension + * is applied over any extension that might have been generated from a + * page title. + */ + const long VALIDATE_FORCE_APPEND_EXTENSION = 64; + /** * Generate a valid filename from the channel that can be used to save * the content of the channel to the local disk. diff --git a/toolkit/content/contentAreaUtils.js b/toolkit/content/contentAreaUtils.js index 68905b0a8e8d..88dced3ac890 100644 --- a/toolkit/content/contentAreaUtils.js +++ b/toolkit/content/contentAreaUtils.js @@ -600,7 +600,7 @@ function initFileInfo( aFI.fileName = mimeService.validateFileNameForSaving( fileName, aContentType, - mimeService.VALIDATE_DEFAULT + mimeService.VALIDATE_FORCE_APPEND_EXTENSION );
// If uriExt is blank, consider: aFI.suggestedFileName is supplied if diff --git a/uriloader/exthandler/nsExternalHelperAppService.cpp b/uriloader/exthandler/nsExternalHelperAppService.cpp index 0fdfe1936a4e..0cfe522d2942 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.cpp +++ b/uriloader/exthandler/nsExternalHelperAppService.cpp @@ -3433,8 +3433,9 @@ nsExternalHelperAppService::ValidateFileNameForSaving( // If an suitable extension was found, we will append to or replace the // existing extension. if (!extension.IsEmpty()) { - ModifyExtensionType modify = - ShouldModifyExtension(mimeInfo, originalExtension); + ModifyExtensionType modify = ShouldModifyExtension( + mimeInfo, aFlags & VALIDATE_FORCE_APPEND_EXTENSION, + originalExtension); if (modify == ModifyExtension_Replace) { int32_t dotidx = fileName.RFind("."); if (dotidx != -1) { @@ -3685,6 +3686,7 @@ void nsExternalHelperAppService::SanitizeFileName(nsAString& aFileName,
nsExternalHelperAppService::ModifyExtensionType nsExternalHelperAppService::ShouldModifyExtension(nsIMIMEInfo* aMimeInfo, + bool aForceAppend, const nsCString& aFileExt) { nsAutoCString MIMEType; if (!aMimeInfo || NS_FAILED(aMimeInfo->GetMIMEType(MIMEType))) { @@ -3709,7 +3711,7 @@ nsExternalHelperAppService::ShouldModifyExtension(nsIMIMEInfo* aMimeInfo, }
if (!canForce) { - return ModifyExtension_Ignore; + return aForceAppend ? ModifyExtension_Append : ModifyExtension_Ignore; } }
diff --git a/uriloader/exthandler/nsExternalHelperAppService.h b/uriloader/exthandler/nsExternalHelperAppService.h index 439be1645f4f..1374d74255b3 100644 --- a/uriloader/exthandler/nsExternalHelperAppService.h +++ b/uriloader/exthandler/nsExternalHelperAppService.h @@ -226,6 +226,7 @@ class nsExternalHelperAppService : public nsIExternalHelperAppService, ModifyExtension_Ignore = 2 }; ModifyExtensionType ShouldModifyExtension(nsIMIMEInfo* aMimeInfo, + bool aForceAppend, const nsCString& aFileExt);
/** diff --git a/uriloader/exthandler/tests/mochitest/browser_save_filenames.js b/uriloader/exthandler/tests/mochitest/browser_save_filenames.js index af4bf421dfe5..7b0f3c6747bc 100644 --- a/uriloader/exthandler/tests/mochitest/browser_save_filenames.js +++ b/uriloader/exthandler/tests/mochitest/browser_save_filenames.js @@ -13,6 +13,7 @@ requestLongerTimeout(8);
let types = { text: "text/plain", + html: "text/html", png: "image/png", jpeg: "image/jpeg", webp: "image/webp", @@ -93,6 +94,10 @@ function handleRequest(aRequest, aResponse) { aResponse.write(JPEG_DATA); } else if (type == "webp") { aResponse.write(WEBP_DATA); + } else if (type == "html") { + aResponse.write( + "<html><head><title>file.inv</title></head><body>File</body></html>" + ); } else { aResponse.write("// Some Text"); } @@ -202,12 +207,14 @@ function getItems(parentid) { elem.localName == "img" && elem.dataset.nodrag != "true"; let unknown = elem.dataset.unknown; let noattach = elem.dataset.noattach; + let savepagename = elem.dataset.savepagename; elements.push({ draggable, unknown, filename, url, noattach, + savepagename, }); elem = elem.nextElementSibling; } @@ -508,7 +515,7 @@ add_task(async function saveas_files() { // filename index.html. let expectedFilename = expectedItems[idx].unknown ? DEFAULT_INDEX_FILENAME - : expectedItems[idx].filename; + : expectedItems[idx].savepagename || expectedItems[idx].filename;
// When saving via contentAreaUtils.js, the content disposition name // field is used as an alternate. @@ -739,6 +746,32 @@ add_task(async function save_download_links() { } });
+add_task(async function save_page_with_invalid_extension() { + await BrowserTestUtils.openNewForegroundTab( + gBrowser, + "http://localhost:8000/save_filename.sjs?type=html" + ); + + let filename = await new Promise(resolve => { + MockFilePicker.showCallback = function(fp) { + setTimeout(() => { + resolve(fp.defaultString); + }, 0); + return Ci.nsIFilePicker.returnCancel; + }; + + document.getElementById("Browser:SavePage").doCommand(); + }); + + is( + filename, + AppConstants.platform == "win" ? "file.inv.htm" : "file.inv.html", + "html extension has been added" + ); + + await BrowserTestUtils.removeTab(gBrowser.selectedTab); +}); + add_task(async () => { BrowserTestUtils.removeTab(gBrowser.selectedTab); MockFilePicker.cleanup(); diff --git a/uriloader/exthandler/tests/mochitest/save_filenames.html b/uriloader/exthandler/tests/mochitest/save_filenames.html index 0d7004515a9b..366e21dab277 100644 --- a/uriloader/exthandler/tests/mochitest/save_filenames.html +++ b/uriloader/exthandler/tests/mochitest/save_filenames.html @@ -88,11 +88,11 @@
<!-- script with invalid extension. --> <script id="i23" src="http://localhost:8000/save_filename.sjs?type=js&filename=script2.exe" - data-filename="script2.exe"></script> + data-filename="script2.exe" data-savepagename="script2.exe.js"></script>
<!-- script with escaped characters --> <script id="i24" src="http://localhost:8000/save_filename.sjs?type=js&filename=script%20%33.ex..." - data-filename="script 3.exe"></script> + data-filename="script 3.exe" data-savepagename="script 3.exe.js"></script>
<!-- script with long filename --> <script id="i25" src="http://localhost:8000/save_filename.sjs?type=js&filename=script123456789..." @@ -152,11 +152,11 @@
<!-- script where url filename has no extension and invalid extension in content disposition filename --> <script id="i41" src="http://localhost:8000/base?type=js&filename=script5.exe" - data-filename="script5.exe"></script> + data-filename="script5.exe" data-savepagename="script5.exe.js"></script>
<!-- script where url filename has no extension and escaped characters in content disposition filename--> <script id="i42" src="http://localhost:8000/base?type=js&filename=script%20%36.exe" - data-filename="script 6.exe"></script> + data-filename="script 6.exe" data-savepagename="script 6.exe.js"></script>
<!-- text where filename is present --> <img id="i43" src="http://localhost:8000/getdata.png?type=text&filename=readme.txt" @@ -292,6 +292,9 @@ <img id="i76" src="http://localhost:8000/executable.exe?type=gook" data-nodrag="true" data-unknown="typeonly" data-filename="executable.exe">
+<!-- embedded child html --> +<object id="i77" data="http://localhost:8000/save_filename.sjs?type=html&filename=child.par" + data-filename="child.par" data-unknown="true"></object> </span>
<!-- This set is used to test the filename specified by the download attribute is validated correctly. -->