browser_mixed_content_download.js (4911B)
1 ChromeUtils.defineESModuleGetters(this, { 2 Downloads: "resource://gre/modules/Downloads.sys.mjs", 3 DownloadsCommon: 4 "moz-src:///browser/components/downloads/DownloadsCommon.sys.mjs", 5 }); 6 7 const HandlerService = Cc[ 8 "@mozilla.org/uriloader/handler-service;1" 9 ].getService(Ci.nsIHandlerService); 10 11 const MIMEService = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService); 12 13 let SECURE_BASE_URL = 14 getRootDirectory(gTestPath).replace( 15 "chrome://mochitests/content/", 16 "https://example.com/" 17 ) + "download_page.html"; 18 19 /** 20 * Waits until a download is triggered. 21 * It waits until a prompt is shown, 22 * saves and then accepts the dialog. 23 * 24 * @returns {Promise} Resolved once done. 25 */ 26 27 function shouldTriggerDownload() { 28 return new Promise((resolve, reject) => { 29 Services.wm.addListener({ 30 onOpenWindow(xulWin) { 31 Services.wm.removeListener(this); 32 let win = xulWin.docShell.domWindow; 33 waitForFocus(() => { 34 if ( 35 win.location == 36 "chrome://mozapps/content/downloads/unknownContentType.xhtml" 37 ) { 38 let dialog = win.document.getElementById("unknownContentType"); 39 let button = dialog.getButton("accept"); 40 let actionRadio = win.document.getElementById("save"); 41 actionRadio.click(); 42 button.disabled = false; 43 dialog.acceptDialog(); 44 resolve(); 45 } else { 46 reject(); 47 } 48 }, win); 49 }, 50 }); 51 }); 52 } 53 54 const CONSOLE_UPGRADE_MESSAGE = "Upgrading insecure request"; 55 const CONSOLE_DOWNGRADE_MESSAGE = "Downgrading to “http” again."; 56 const DOWNLOAD_URL = 57 "example.com/browser/dom/security/test/https-first/download_server.sjs"; 58 // Verifies that https-first tries to upgrade download, 59 // falls back since download is not available via https 60 let msgCounter = 0; 61 function shouldConsoleError() { 62 return new Promise(resolve => { 63 function listener(msgObj) { 64 let text = msgObj.message; 65 if (text.includes(CONSOLE_UPGRADE_MESSAGE) && msgCounter == 0) { 66 ok( 67 text.includes("http://" + DOWNLOAD_URL), 68 "Https-first tries to upgrade download to https" 69 ); 70 msgCounter++; 71 } 72 if (text.includes(CONSOLE_DOWNGRADE_MESSAGE) && msgCounter == 1) { 73 ok( 74 text.includes("https://" + DOWNLOAD_URL), 75 "Https-first downgrades download to http." 76 ); 77 resolve(); 78 Services.console.unregisterListener(listener); 79 } 80 } 81 Services.console.registerListener(listener); 82 }); 83 } 84 85 async function resetDownloads() { 86 // Removes all downloads from the download List 87 const types = new Set(); 88 let publicList = await Downloads.getList(Downloads.PUBLIC); 89 let downloads = await publicList.getAll(); 90 for (let download of downloads) { 91 if (download.contentType) { 92 types.add(download.contentType); 93 } 94 publicList.remove(download); 95 await download.finalize(true); 96 } 97 98 if (types.size) { 99 // reset handlers for the contentTypes of any files previously downloaded 100 for (let type of types) { 101 const mimeInfo = MIMEService.getFromTypeAndExtension(type, ""); 102 info("resetting handler for type: " + type); 103 HandlerService.remove(mimeInfo); 104 } 105 } 106 } 107 108 async function runTest(url, link, checkFunction, description) { 109 await SpecialPowers.pushPrefEnv({ 110 set: [ 111 ["dom.security.https_first", true], 112 ["browser.download.always_ask_before_handling_new_types", true], 113 ], 114 }); 115 requestLongerTimeout(2); 116 await resetDownloads(); 117 118 let tab = BrowserTestUtils.addTab(gBrowser, url); 119 gBrowser.selectedTab = tab; 120 121 let browser = gBrowser.getBrowserForTab(tab); 122 await BrowserTestUtils.browserLoaded(browser); 123 is( 124 gBrowser.currentURI.schemeIs("https"), 125 true, 126 "Scheme of opened tab should be https" 127 ); 128 info("Checking: " + description); 129 130 let checkPromise = checkFunction(); 131 // Click the Link to trigger the download 132 SpecialPowers.spawn(gBrowser.selectedBrowser, [link], contentLink => { 133 content.document.getElementById(contentLink).click(); 134 }); 135 await checkPromise; 136 ok(true, description); 137 BrowserTestUtils.removeTab(tab); 138 } 139 140 //Test description: 141 // 1. Open "https://example.com" 142 // 2. From "https://example.com" download something, but that download is only available via http. 143 // 3. Https-first tries to upgrade the download. 144 // 4. Upgrading fails - so http-first downgrade download to http. 145 146 add_task(async function test_mixed_download() { 147 await runTest( 148 SECURE_BASE_URL, 149 "insecure", 150 () => Promise.all([shouldTriggerDownload(), shouldConsoleError()]), 151 "Secure -> Insecure should Error" 152 ); 153 // remove downloaded file 154 let downloadsPromise = Downloads.getList(Downloads.PUBLIC); 155 let downloadList = await downloadsPromise; 156 let [download] = downloadList._downloads; 157 await downloadList.remove(download); 158 });