From d7b660230f8e7aede72ed8d101f313578cfbd6ae Mon Sep 17 00:00:00 2001 From: Andreas Farre Date: Thu, 23 Apr 2020 13:56:08 +0000 Subject: [PATCH] Bug 1576188 - Test that save-as works for cross process frames. r=peterv Differential Revision: https://phabricator.services.mozilla.com/D70388 --- dom/tests/browser/browser.ini | 6 +- dom/tests/browser/browser_persist_cookies.js | 4 +- .../browser_persist_cross_origin_iframe.js | 193 ++++++++++++++++++ dom/tests/browser/image.html | 2 + 4 files changed, 202 insertions(+), 3 deletions(-) create mode 100644 dom/tests/browser/browser_persist_cross_origin_iframe.js create mode 100644 dom/tests/browser/image.html diff --git a/dom/tests/browser/browser.ini b/dom/tests/browser/browser.ini index 67fe62dd810c..397614ad1c79 100644 --- a/dom/tests/browser/browser.ini +++ b/dom/tests/browser/browser.ini @@ -10,6 +10,7 @@ support-files = worker_bug1004814.js geo_leak_test.html dummy.html + dummy.png test_largeAllocation.html test_largeAllocation.html^headers^ test_largeAllocation2.html @@ -71,12 +72,10 @@ skip-if = 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 @@ -109,3 +108,6 @@ skip-if = webrender support-files = file_postMessage_parent.html [browser_navigate_replace_browsingcontext.js] +[browser_persist_cross_origin_iframe.js] +support-files = + image.html diff --git a/dom/tests/browser/browser_persist_cookies.js b/dom/tests/browser/browser_persist_cookies.js index 58cfead02135..feafd9d9a282 100644 --- a/dom/tests/browser/browser_persist_cookies.js +++ b/dom/tests/browser/browser_persist_cookies.js @@ -98,7 +98,7 @@ add_task(async function() { info("done showCallback"); }; saveBrowser(browser); - await new Promise(async resolve => { + await new Promise(async (resolve, reject) => { let dls = await Downloads.getList(Downloads.PUBLIC); dls.addView({ onDownloadChanged(download) { @@ -106,6 +106,8 @@ add_task(async function() { dls.removeView(this); dls.removeFinished(); resolve(); + } else if (download.error) { + reject("Download failed"); } }, }); diff --git a/dom/tests/browser/browser_persist_cross_origin_iframe.js b/dom/tests/browser/browser_persist_cross_origin_iframe.js new file mode 100644 index 000000000000..27a3edf82a92 --- /dev/null +++ b/dom/tests/browser/browser_persist_cross_origin_iframe.js @@ -0,0 +1,193 @@ +/* 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" +); +const TEST_PATH2 = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content", + "https://example.com" +); + +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()) { + saveDir.create(Ci.nsIFile.DIRECTORY_TYPE, 0o755); + } + return saveDir; +} + +function checkContents(dir, expected, str) { + let stack = [dir]; + let files = []; + while (stack.length) { + for (let file of stack.pop().directoryEntries) { + if (file.isDirectory()) { + stack.push(file); + } + + files.push(file.path); + } + } + + SimpleTest.isDeeply( + files.sort(), + expected.sort(), + str + "Should contain downloaded files in correct place." + ); +} + +async function addFrame(browser, path, selector) { + await SpecialPowers.spawn(browser, [path, selector], async function( + path, + selector + ) { + let document = content.document; + let target = document.querySelector(selector); + if (target instanceof content.HTMLIFrameElement) { + document = target.contentDocument; + target = document.body; + } + let element = document.createElement("iframe"); + element.src = path; + await new Promise(resolve => { + element.onload = resolve; + target.appendChild(element); + }); + }); +} + +async function handleResult(expected, str) { + let dls = await Downloads.getList(Downloads.PUBLIC); + return new Promise((resolve, reject) => { + dls.addView({ + onDownloadChanged(download) { + if (download.succeeded) { + checkContents(gTestDir, expected, str); + + dls.removeView(this); + dls.removeFinished(); + resolve(); + } else if (download.error) { + reject("Download failed"); + } + }, + }); + }); +} + +add_task(async function() { + await BrowserTestUtils.withNewTab(TEST_PATH + "image.html", async function( + browser + ) { + await addFrame(browser, TEST_PATH + "image.html", "body"); + await addFrame(browser, TEST_PATH2 + "image.html", "body>iframe"); + + gTestDir = createTemporarySaveDirectory(); + + MockFilePicker.displayDirectory = gTestDir; + MockFilePicker.showCallback = function(fp) { + let destFile = gTestDir.clone(); + destFile.append("first.html"); + MockFilePicker.setFiles([destFile]); + MockFilePicker.filterIndex = 0; // kSaveAsType_Complete + }; + + let expected = [ + "/tmp/testsavedir/first.html", + "/tmp/testsavedir/first_files", + "/tmp/testsavedir/first_files/image.html", + "/tmp/testsavedir/first_files/dummy.png", + "/tmp/testsavedir/first_files/image_data", + "/tmp/testsavedir/first_files/image_data/image.html", + "/tmp/testsavedir/first_files/image_data/image_data", + "/tmp/testsavedir/first_files/image_data/image_data/dummy.png", + ]; + + // This saves the top-level document contained in `browser` + saveBrowser(browser); + await handleResult(expected, "Check toplevel: "); + + // Instead of deleting previously saved files, we update our list + // of expected files for the next part of the test. To not clash + // we make sure to save to a different file name. + expected = expected.concat([ + "/tmp/testsavedir/second.html", + "/tmp/testsavedir/second_files", + "/tmp/testsavedir/second_files/dummy.png", + "/tmp/testsavedir/second_files/image.html", + "/tmp/testsavedir/second_files/image_data", + "/tmp/testsavedir/second_files/image_data/dummy.png", + ]); + + MockFilePicker.displayDirectory = gTestDir; + MockFilePicker.showCallback = function(fp) { + let destFile = gTestDir.clone(); + destFile.append("second.html"); + MockFilePicker.setFiles([destFile]); + MockFilePicker.filterIndex = 0; // kSaveAsType_Complete + }; + + // This saves the sub-document of the iframe contained in the + // top-level document, as indicated by passing a child browsing + // context as target for the save. + saveBrowser(browser, false, browser.browsingContext.children[0]); + await handleResult(expected, "Check subframe: "); + + // Instead of deleting previously saved files, we update our list + // of expected files for the next part of the test. To not clash + // we make sure to save to a different file name. + expected = expected.concat([ + "/tmp/testsavedir/third.html", + "/tmp/testsavedir/third_files", + "/tmp/testsavedir/third_files/dummy.png", + ]); + + MockFilePicker.displayDirectory = gTestDir; + MockFilePicker.showCallback = function(fp) { + let destFile = gTestDir.clone(); + destFile.append("third.html"); + MockFilePicker.setFiles([destFile]); + MockFilePicker.filterIndex = 0; // kSaveAsType_Complete + }; + + // This saves the sub-document of the iframe contained in the + // first sub-document, as indicated by passing a child browsing + // context as target for the save. That frame is special, because + // it's cross-process. + saveBrowser( + browser, + false, + browser.browsingContext.children[0].children[0] + ); + await handleResult(expected, "Check subframe: "); + }); +}); diff --git a/dom/tests/browser/image.html b/dom/tests/browser/image.html new file mode 100644 index 000000000000..843ebfd1b599 --- /dev/null +++ b/dom/tests/browser/image.html @@ -0,0 +1,2 @@ + +