mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-19 08:15:31 +00:00
Bug 1508355 - Add a test case for assuring all "Save ... As" options honor the first party domain. r=baku,richard@torproject.org
This patch adds a test case which tests following "Save ... As" options: * File menu: - Save Page As * Context menu in content pages: - Save Page As - Save Image As - Save Video As - Save Link As - Save Frame As * Page Info "Media" Panel: - Save As It triggers the save process and checks if the OA of the saving channel has the correct first party domain.
This commit is contained in:
parent
92a09b4912
commit
58f7b5b978
@ -14,6 +14,7 @@ support-files =
|
||||
file_firstPartyBasic.html
|
||||
file_postMessage.html
|
||||
file_postMessageSender.html
|
||||
file_saveAs.sjs
|
||||
file_sharedworker.html
|
||||
file_sharedworker.js
|
||||
file_thirdPartyChild.audio.ogg
|
||||
@ -59,6 +60,7 @@ support-files =
|
||||
window_redirect.html
|
||||
worker_blobify.js
|
||||
worker_deblobify.js
|
||||
!/toolkit/content/tests/browser/common/mockTransfer.js
|
||||
|
||||
[browser_broadcastChannel.js]
|
||||
[browser_cache.js]
|
||||
@ -72,6 +74,7 @@ skip-if = debug #Bug 1345346
|
||||
[browser_firstPartyIsolation_aboutPages.js]
|
||||
[browser_firstPartyIsolation_blobURI.js]
|
||||
[browser_firstPartyIsolation_js_uri.js]
|
||||
[browser_firstPartyIsolation_saveAs.js]
|
||||
[browser_localStorageIsolation.js]
|
||||
[browser_blobURLIsolation.js]
|
||||
skip-if = (verify && debug && (os == 'win'))
|
||||
|
@ -0,0 +1,266 @@
|
||||
/**
|
||||
* Bug 1508355 - A test case for ensuring the saving channel has a correct first
|
||||
* party domain when going through different "Save ... AS."
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
/* import-globals-from ../../../../../toolkit/content/tests/browser/common/mockTransfer.js */
|
||||
Services.scriptloader
|
||||
.loadSubScript("chrome://mochitests/content/browser/toolkit/content/tests/browser/common/mockTransfer.js",
|
||||
this);
|
||||
|
||||
const TEST_FIRST_PARTY = "example.com";
|
||||
const TEST_ORIGIN = `http://${TEST_FIRST_PARTY}`;
|
||||
const TEST_BASE_PATH = "/browser/browser/components/originattributes/test/browser/";
|
||||
const TEST_PATH = `${TEST_BASE_PATH}file_saveAs.sjs`;
|
||||
const TEST_PATH_VIDEO = `${TEST_BASE_PATH}file_thirdPartyChild.video.ogv`;
|
||||
const TEST_PATH_IMAGE = `${TEST_BASE_PATH}file_favicon.png`;
|
||||
|
||||
// For the "Save Page As" test, we will check the channel of the sub-resource
|
||||
// within the page. In this case, it is a image.
|
||||
const TEST_PATH_PAGE = `${TEST_BASE_PATH}file_favicon.png`;
|
||||
|
||||
// For the "Save Frame As" test, we will check the channel of the sub-resource
|
||||
// within the frame. In this case, it is a image.
|
||||
const TEST_PATH_FRAME = `${TEST_BASE_PATH}file_favicon.png`;
|
||||
|
||||
let MockFilePicker = SpecialPowers.MockFilePicker;
|
||||
MockFilePicker.init(window);
|
||||
|
||||
add_task(async function setup() {
|
||||
info("Setting the prefs.");
|
||||
|
||||
await SpecialPowers.pushPrefEnv({"set": [
|
||||
["privacy.firstparty.isolate", true],
|
||||
]});
|
||||
|
||||
info("Setting MockFilePicker.");
|
||||
let tempDir = createTemporarySaveDirectory();
|
||||
|
||||
MockFilePicker.displayDirectory = tempDir;
|
||||
MockFilePicker.showCallback = fp => {
|
||||
info("MockFilePicker showCallback");
|
||||
|
||||
let fileName = fp.defaultString;
|
||||
let destFile = tempDir.clone();
|
||||
destFile.append(fileName);
|
||||
|
||||
MockFilePicker.setFiles([destFile]);
|
||||
MockFilePicker.filterIndex = 0; // kSaveAsType_Complete
|
||||
|
||||
info("MockFilePicker showCallback done");
|
||||
};
|
||||
|
||||
mockTransferRegisterer.register();
|
||||
|
||||
registerCleanupFunction(function() {
|
||||
mockTransferRegisterer.unregister();
|
||||
MockFilePicker.cleanup();
|
||||
tempDir.remove(true);
|
||||
});
|
||||
});
|
||||
|
||||
function createTemporarySaveDirectory() {
|
||||
let saveDir = Services.dirsvc.get("TmpD", Ci.nsIFile);
|
||||
saveDir.append("testsavedir");
|
||||
saveDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0o755);
|
||||
return saveDir;
|
||||
}
|
||||
|
||||
function createPromiseForObservingChannel(aURL, aFirstParty) {
|
||||
return new Promise(resolve => {
|
||||
let observer = (aSubject, aTopic) => {
|
||||
if (aTopic === "http-on-modify-request") {
|
||||
let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
|
||||
let reqLoadInfo = httpChannel.loadInfo;
|
||||
|
||||
// Make sure this is the request which we want to check.
|
||||
if (!httpChannel.URI.spec.endsWith(aURL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
info(`Checking loadInfo for URI: ${httpChannel.URI.spec}\n`);
|
||||
is(reqLoadInfo.originAttributes.firstPartyDomain, aFirstParty,
|
||||
"The loadInfo has correct first party domain");
|
||||
|
||||
Services.obs.removeObserver(observer, "http-on-modify-request");
|
||||
resolve();
|
||||
}
|
||||
};
|
||||
|
||||
Services.obs.addObserver(observer, "http-on-modify-request");
|
||||
});
|
||||
}
|
||||
|
||||
function createPromiseForTransferComplete() {
|
||||
return new Promise((resolve) => {
|
||||
function onTransferComplete(downloadSuccess) {
|
||||
ok(downloadSuccess, "File should have been downloaded successfully");
|
||||
// Clear the callback for now.
|
||||
mockTransferCallback = () => { };
|
||||
resolve();
|
||||
}
|
||||
|
||||
mockTransferCallback = onTransferComplete;
|
||||
});
|
||||
}
|
||||
|
||||
async function doCommandForFrameType() {
|
||||
info("Opening the frame sub-menu under the context menu.");
|
||||
let contextMenu = document.getElementById("contentAreaContextMenu");
|
||||
let frameMenuPopup = contextMenu.querySelector("#frame").menupopup;
|
||||
let frameMenuPopupPromise = BrowserTestUtils.waitForEvent(frameMenuPopup,
|
||||
"popupshown");
|
||||
|
||||
frameMenuPopup.openPopup();
|
||||
await frameMenuPopupPromise;
|
||||
|
||||
info("Triggering the save process.");
|
||||
let saveFrameCommand = contextMenu.querySelector("#context-saveframe");
|
||||
saveFrameCommand.doCommand();
|
||||
}
|
||||
|
||||
add_task(async function testContextMenuSaveAs() {
|
||||
const TEST_DATA = [
|
||||
{ type: "link", path: TEST_PATH, target: "#link1" },
|
||||
{ type: "video", path: TEST_PATH_VIDEO, target: "#video1" },
|
||||
{ type: "image", path: TEST_PATH_IMAGE, target: "#image1" },
|
||||
{ type: "page", path: TEST_PATH_PAGE, target: "body" },
|
||||
{ type: "frame", path: TEST_PATH_FRAME, target: "#frame1",
|
||||
doCommandFunc: doCommandForFrameType },
|
||||
];
|
||||
|
||||
for (const data of TEST_DATA) {
|
||||
info(`Open a new tab for testing "Save ${data.type} as" in context menu.`);
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser,
|
||||
`${TEST_ORIGIN}${TEST_PATH}?${data.type}=1`);
|
||||
|
||||
let popupShownPromise = BrowserTestUtils.waitForEvent(document, "popupshown");
|
||||
|
||||
info("Open the context menu.");
|
||||
await BrowserTestUtils.synthesizeMouseAtCenter(data.target, {
|
||||
type: "contextmenu",
|
||||
button: 2,
|
||||
},
|
||||
gBrowser.selectedBrowser);
|
||||
|
||||
await popupShownPromise;
|
||||
|
||||
let transferCompletePromise = createPromiseForTransferComplete();
|
||||
let observerPromise = createPromiseForObservingChannel(data.path, TEST_FIRST_PARTY);
|
||||
|
||||
// Select "Save As" option from context menu.
|
||||
if (!data.doCommandFunc) {
|
||||
let saveElement = document.getElementById(`context-save${data.type}`);
|
||||
info("Triggering the save process.");
|
||||
saveElement.doCommand();
|
||||
} else {
|
||||
await data.doCommandFunc();
|
||||
}
|
||||
|
||||
info("Waiting for the channel.");
|
||||
await observerPromise;
|
||||
|
||||
info("Close the context menu.");
|
||||
let contextMenu = document.getElementById("contentAreaContextMenu");
|
||||
let popupHiddenPromise = BrowserTestUtils.waitForEvent(contextMenu, "popuphidden");
|
||||
contextMenu.hidePopup();
|
||||
await popupHiddenPromise;
|
||||
|
||||
info("Wait until the save is finished.");
|
||||
await transferCompletePromise;
|
||||
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
}
|
||||
});
|
||||
|
||||
add_task(async function testFileMenuSavePageAs() {
|
||||
info(`Open a new tab for testing "Save Page AS" in the file menu.`);
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser,
|
||||
`${TEST_ORIGIN}${TEST_PATH}?page=1`);
|
||||
|
||||
let transferCompletePromise = createPromiseForTransferComplete();
|
||||
let observerPromise = createPromiseForObservingChannel(TEST_PATH_PAGE, TEST_FIRST_PARTY);
|
||||
|
||||
let menubar = document.getElementById("main-menubar");
|
||||
let filePopup = document.getElementById("menu_FilePopup");
|
||||
|
||||
// We only use the shortcut keys to open the file menu in Windows and Linux.
|
||||
// Mac doesn't have a shortcut to only open the file menu. Instead, we directly
|
||||
// trigger the save in MAC without any UI interactions.
|
||||
if (Services.appinfo.OS !== "Darwin") {
|
||||
let menubarActive = BrowserTestUtils.waitForEvent(menubar, "DOMMenuBarActive");
|
||||
EventUtils.synthesizeKey("KEY_F10");
|
||||
await menubarActive;
|
||||
|
||||
let popupShownPromise = BrowserTestUtils.waitForEvent(filePopup, "popupshown");
|
||||
// In window, it still needs one extra down key to open the file menu.
|
||||
if (Services.appinfo.OS === "WINNT") {
|
||||
EventUtils.synthesizeKey("KEY_ArrowDown");
|
||||
}
|
||||
await popupShownPromise;
|
||||
}
|
||||
|
||||
info("Triggering the save process.");
|
||||
let fileSavePageAsElement = document.getElementById("menu_savePage");
|
||||
fileSavePageAsElement.doCommand();
|
||||
|
||||
info("Waiting for the channel.");
|
||||
await observerPromise;
|
||||
|
||||
// Close the file menu.
|
||||
if (Services.appinfo.OS !== "Darwin") {
|
||||
let popupHiddenPromise = BrowserTestUtils.waitForEvent(filePopup, "popuphidden");
|
||||
filePopup.hidePopup();
|
||||
await popupHiddenPromise;
|
||||
}
|
||||
|
||||
info("Wait until the save is finished.");
|
||||
await transferCompletePromise;
|
||||
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
});
|
||||
|
||||
add_task(async function testPageInfoMediaSaveAs() {
|
||||
info(`Open a new tab for testing "Save AS" in the media panel of the page info.`);
|
||||
let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser,
|
||||
`${TEST_ORIGIN}${TEST_PATH}?pageinfo=1`);
|
||||
|
||||
info("Open the media panel of the pageinfo.");
|
||||
let pageInfo = BrowserPageInfo(gBrowser.selectedBrowser.currentURI.spec,
|
||||
"mediaTab");
|
||||
|
||||
await BrowserTestUtils.waitForEvent(pageInfo, "load");
|
||||
await new Promise(resolve => pageInfo.onFinished.push(() => executeSoon(resolve)));
|
||||
|
||||
let imageTree = pageInfo.document.getElementById("imagetree");
|
||||
let imageRowsNum = imageTree.view.rowCount;
|
||||
|
||||
is(imageRowsNum, 2, "There should be two media items here.");
|
||||
|
||||
for (let i = 0; i < imageRowsNum; i++) {
|
||||
imageTree.view.selection.select(i);
|
||||
imageTree.ensureRowIsVisible(i);
|
||||
imageTree.focus();
|
||||
|
||||
let url = pageInfo.gImageView.data[i][0]; // COL_IMAGE_ADDRESS
|
||||
info(`Start to save the media item with URL: ${url}`);
|
||||
|
||||
let transferCompletePromise = createPromiseForTransferComplete();
|
||||
let observerPromise = createPromiseForObservingChannel(url, TEST_FIRST_PARTY);
|
||||
|
||||
info("Triggering the save process.");
|
||||
let saveElement = pageInfo.document.getElementById("imagesaveasbutton");
|
||||
saveElement.doCommand();
|
||||
|
||||
info("Waiting for the channel.");
|
||||
await observerPromise;
|
||||
|
||||
info("Wait until the save is finished.");
|
||||
await transferCompletePromise;
|
||||
}
|
||||
|
||||
pageInfo.close();
|
||||
BrowserTestUtils.removeTab(tab);
|
||||
});
|
@ -0,0 +1,40 @@
|
||||
const HTTP_ORIGIN = "http://example.com";
|
||||
const SECOND_ORIGIN = "http://example.org";
|
||||
const URI_PATH = "/browser/browser/components/originattributes/test/browser/";
|
||||
const LINK_PATH = `${URI_PATH}file_saveAs.sjs`;
|
||||
// Reusing existing ogv file for testing.
|
||||
const VIDEO_PATH = `${URI_PATH}file_thirdPartyChild.video.ogv`;
|
||||
// Reusing existing png file for testing.
|
||||
const IMAGE_PATH = `${URI_PATH}file_favicon.png`;
|
||||
const FRAME_PATH = `${SECOND_ORIGIN}${URI_PATH}file_saveAs.sjs?image=1`
|
||||
|
||||
Components.utils.importGlobalProperties(["URLSearchParams"]);
|
||||
|
||||
function handleRequest(aRequest, aResponse) {
|
||||
var params = new URLSearchParams(aRequest.queryString);
|
||||
aResponse.setStatusLine(aRequest.httpVersion, 200);
|
||||
aResponse.setHeader("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
let contentBody = "";
|
||||
|
||||
if (params.has("link")) {
|
||||
contentBody = `<a href="${LINK_PATH}" id="link1">this is a link</a>`;
|
||||
} else if (params.has("video")) {
|
||||
contentBody = `<video src="${VIDEO_PATH}" id="video1"> </video>`;
|
||||
} else if (params.has("image")) {
|
||||
contentBody = `<img src="${IMAGE_PATH}" id="image1">`;
|
||||
} else if (params.has("page")) {
|
||||
// We need at least one resource, like a img, a link or a script, to trigger
|
||||
// downloading resources in "Save Page As". Otherwise, it will output the
|
||||
// document directly without any network request.
|
||||
contentBody = `<img src="${IMAGE_PATH}">`;
|
||||
} else if (params.has("frame")) {
|
||||
// Like "Save Page As", we need to put at least one resource in the frame.
|
||||
// Here we also use a image.
|
||||
contentBody = `<iframe src="${FRAME_PATH}" id="frame1"></iframe>`;
|
||||
} else if (params.has("pageinfo")) {
|
||||
contentBody = `<img src="${IMAGE_PATH}" id="image1">
|
||||
<video src="${VIDEO_PATH}" id="video1"> </video>`;
|
||||
}
|
||||
|
||||
aResponse.write(`<html><body>${contentBody}</body></html>`);
|
||||
}
|
Loading…
Reference in New Issue
Block a user