browser_save_as.js (5660B)
1 "use strict"; 2 3 Services.scriptloader.loadSubScript( 4 "chrome://mochitests/content/browser/toolkit/content/tests/browser/common/mockTransfer.js", 5 this 6 ); 7 8 // Using insecure HTTP URL for a test cases around HTTP/HTTPS download interaction 9 // eslint-disable-next-line @microsoft/sdl/no-insecure-url 10 const HTTP_LINK = `http://example.org/`; 11 const HTTPS_LINK = `https://example.org/`; 12 const TEST_PATH = 13 // eslint-disable-next-line @microsoft/sdl/no-insecure-url 14 "http://example.com/browser/dom/security/test/https-only/file_save_as.html"; 15 16 let MockFilePicker = SpecialPowers.MockFilePicker; 17 MockFilePicker.init(window.browsingContext); 18 const tempDir = createTemporarySaveDirectory(); 19 MockFilePicker.displayDirectory = tempDir; 20 21 add_setup(async function () { 22 await SpecialPowers.pushPrefEnv({ 23 set: [["test.wait300msAfterTabSwitch", true]], 24 }); 25 26 info("Setting MockFilePicker."); 27 mockTransferRegisterer.register(); 28 29 registerCleanupFunction(function () { 30 mockTransferRegisterer.unregister(); 31 MockFilePicker.cleanup(); 32 tempDir.remove(true); 33 }); 34 }); 35 36 function createTemporarySaveDirectory() { 37 let saveDir = Services.dirsvc.get("TmpD", Ci.nsIFile); 38 saveDir.append("testsavedir"); 39 saveDir.createUnique(Ci.nsIFile.DIRECTORY_TYPE, 0o755); 40 return saveDir; 41 } 42 43 function createPromiseForObservingChannel(expectedUrl) { 44 return new Promise(resolve => { 45 let observer = (aSubject, aTopic) => { 46 if (aTopic === "http-on-modify-request") { 47 let httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel); 48 49 if (httpChannel.URI.spec != expectedUrl) { 50 return; 51 } 52 53 Services.obs.removeObserver(observer, "http-on-modify-request"); 54 resolve(); 55 } 56 }; 57 58 Services.obs.addObserver(observer, "http-on-modify-request"); 59 }); 60 } 61 62 function createPromiseForTransferComplete() { 63 return new Promise(resolve => { 64 MockFilePicker.showCallback = fp => { 65 info("MockFilePicker showCallback"); 66 67 let fileName = fp.defaultString; 68 let destFile = tempDir.clone(); 69 destFile.append(fileName); 70 71 MockFilePicker.setFiles([destFile]); 72 MockFilePicker.filterIndex = 0; // kSaveAsType_Complete 73 74 MockFilePicker.showCallback = null; 75 mockTransferCallback = function (downloadSuccess) { 76 ok(downloadSuccess, "File should have been downloaded successfully"); 77 mockTransferCallback = () => {}; 78 resolve(); 79 }; 80 }; 81 }); 82 } 83 84 function createPromiseForConsoleError(message) { 85 return new Promise(resolve => { 86 function listener(msgObj) { 87 let text = msgObj.message; 88 if (text.includes(message)) { 89 info(`Found occurence of '${message}'`); 90 Services.console.unregisterListener(listener); 91 resolve(); 92 } 93 } 94 Services.console.registerListener(listener); 95 }); 96 } 97 98 async function runTest(selector, expectedUrl, expectedError) { 99 info(`Open a new tab for testing "Save link as" in context menu.`); 100 let tab = await BrowserTestUtils.openNewForegroundTab(gBrowser, TEST_PATH); 101 102 let popupShownPromise = BrowserTestUtils.waitForEvent(document, "popupshown"); 103 104 let browser = gBrowser.selectedBrowser; 105 106 info("Open the context menu."); 107 await BrowserTestUtils.synthesizeMouseAtCenter( 108 selector, 109 { 110 type: "contextmenu", 111 button: 2, 112 }, 113 browser 114 ); 115 116 await popupShownPromise; 117 118 let downloadEndPromise = expectedError 119 ? createPromiseForConsoleError(expectedError) 120 : createPromiseForTransferComplete(); 121 let observerPromise = createPromiseForObservingChannel(expectedUrl); 122 123 let contextMenu = document.getElementById("contentAreaContextMenu"); 124 let popupHiddenPromise = BrowserTestUtils.waitForEvent( 125 contextMenu, 126 "popuphidden" 127 ); 128 129 // Select "Save As" option from context menu. 130 let saveElement = document.getElementById(`context-savelink`); 131 info("Triggering the save process."); 132 contextMenu.activateItem(saveElement); 133 134 info("Waiting for the channel."); 135 await observerPromise; 136 137 info( 138 expectedError 139 ? "Waiting for error in console." 140 : "Wait until the save is finished." 141 ); 142 await downloadEndPromise; 143 144 info("Wait until the menu is closed."); 145 await popupHiddenPromise; 146 147 BrowserTestUtils.removeTab(tab); 148 } 149 150 async function setHttpsFirstAndOnlyPrefs(httpsFirst, httpsOnly) { 151 await SpecialPowers.pushPrefEnv({ 152 set: [ 153 ["dom.security.https_first", httpsFirst], 154 ["dom.security.https_only_mode", httpsOnly], 155 ], 156 }); 157 } 158 159 add_task(async function testBaseline() { 160 // Run with HTTPS-First and HTTPS-Only disabled 161 await setHttpsFirstAndOnlyPrefs(false, false); 162 await runTest("#insecure-link", HTTP_LINK, undefined); 163 await runTest("#secure-link", HTTPS_LINK, undefined); 164 }); 165 166 add_task(async function testHttpsFirst() { 167 // Run with HTTPS-First enabled 168 // The the user will get a warning about really wanting to download 169 // from a insecure site, because we upgraded the top level document, 170 // but the download is still insecure. In the future we also want to 171 // upgrade these Save-As downloads. 172 await setHttpsFirstAndOnlyPrefs(true, false); 173 await runTest( 174 "#insecure-link", 175 HTTP_LINK, 176 "Blocked downloading insecure content “http://example.org/”." 177 ); 178 await runTest("#secure-link", HTTPS_LINK, undefined); 179 }); 180 181 add_task(async function testHttpsOnly() { 182 // Run with HTTPS-Only enabled 183 // Should have same behaviour as HTTPS-First 184 await setHttpsFirstAndOnlyPrefs(false, true); 185 await runTest( 186 "#insecure-link", 187 HTTP_LINK, 188 "Blocked downloading insecure content “http://example.org/”." 189 ); 190 await runTest("#secure-link", HTTPS_LINK, undefined); 191 });