browser_contentOrigins.js (6505B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 const { PromptTestUtils } = ChromeUtils.importESModule( 7 "resource://testing-common/PromptTestUtils.sys.mjs" 8 ); 9 10 let { HttpServer } = ChromeUtils.importESModule( 11 "resource://testing-common/httpd.sys.mjs" 12 ); 13 14 const TEST_ROOT = getRootDirectory(gTestPath).replace( 15 "chrome://mochitests/content", 16 "https://example.com" 17 ); 18 19 const DEFAULT_FAVICON = "chrome://global/skin/icons/defaultFavicon.svg"; 20 const BROKEN_FAVICON = "chrome://global/skin/icons/security-broken.svg"; 21 22 async function checkAlert( 23 pageToLoad, 24 expectedTitle, 25 expectedIcon = DEFAULT_FAVICON 26 ) { 27 function openFn(browser) { 28 return SpecialPowers.spawn(browser, [], () => { 29 if (content.document.nodePrincipal.isSystemPrincipal) { 30 // Can't eval in privileged contexts due to CSP, just call directly: 31 content.alert("Test"); 32 } else { 33 // Eval everywhere else so it gets the principal of the loaded page. 34 content.eval("alert('Test')"); 35 } 36 }); 37 } 38 return checkDialog(pageToLoad, openFn, expectedTitle, expectedIcon); 39 } 40 41 async function checkBeforeunload( 42 pageToLoad, 43 expectedTitle, 44 expectedIcon = DEFAULT_FAVICON 45 ) { 46 async function openFn(browser) { 47 let tab = gBrowser.getTabForBrowser(browser); 48 await BrowserTestUtils.synthesizeMouseAtCenter( 49 "body", 50 {}, 51 browser.browsingContext 52 ); 53 return gBrowser.removeTab(tab); // trigger beforeunload. 54 } 55 return checkDialog(pageToLoad, openFn, expectedTitle, expectedIcon); 56 } 57 58 async function checkDialog( 59 pageToLoad, 60 openFn, 61 expectedTitle, 62 expectedIcon, 63 modalType = Ci.nsIPrompt.MODAL_TYPE_CONTENT 64 ) { 65 return BrowserTestUtils.withNewTab(pageToLoad, async browser => { 66 let promptPromise = PromptTestUtils.waitForPrompt(browser, { 67 modalType, 68 }); 69 let spawnPromise = openFn(browser); 70 let dialog = await promptPromise; 71 72 let doc = dialog.ui.prompt.document; 73 let titleEl = doc.getElementById("titleText"); 74 if (expectedTitle.value) { 75 is(titleEl.textContent, expectedTitle.value, "Title should match."); 76 } else { 77 is( 78 titleEl.dataset.l10nId, 79 expectedTitle.l10nId, 80 "Title l10n id should match." 81 ); 82 } 83 ok( 84 !titleEl.parentNode.hasAttribute("overflown"), 85 "Title should fit without overflowing." 86 ); 87 88 ok(BrowserTestUtils.isVisible(titleEl), "New title should be shown."); 89 ok( 90 BrowserTestUtils.isHidden(doc.getElementById("infoTitle")), 91 "Old title should be hidden." 92 ); 93 let iconCS = doc.ownerGlobal.getComputedStyle( 94 doc.querySelector(".titleIcon") 95 ); 96 Assert.stringContains( 97 iconCS.backgroundImage, 98 expectedIcon, 99 "Icon is as expected." 100 ); 101 102 // This is not particularly neat, but we want to also test overflow 103 // Our test systems don't have hosts that long, so just fake it: 104 if (browser.currentURI.asciiHost == "example.com") { 105 let longerDomain = "extravagantly.long.".repeat(10) + "example.com"; 106 doc.documentElement.setAttribute( 107 "headertitle", 108 JSON.stringify({ raw: longerDomain, shouldUseMaskFade: true }) 109 ); 110 info("Wait for the prompt title to update."); 111 await BrowserTestUtils.waitForMutationCondition( 112 titleEl, 113 { characterData: true, attributes: true }, 114 () => 115 titleEl.textContent == longerDomain && 116 titleEl.parentNode.hasAttribute("overflown") 117 ); 118 is(titleEl.textContent, longerDomain, "The longer domain is reflected."); 119 ok( 120 titleEl.parentNode.hasAttribute("overflown"), 121 "The domain should overflow." 122 ); 123 } 124 125 // Close the prompt again. 126 await PromptTestUtils.handlePrompt(dialog); 127 // The alert in the content process was sync, we need to make sure it gets 128 // cleaned up, but couldn't await it above because that'd hang the test! 129 await spawnPromise; 130 }); 131 } 132 133 add_task(async function test_check_prompt_origin_display() { 134 await checkAlert("https://example.com/", { value: "example.com" }); 135 // eslint-disable-next-line @microsoft/sdl/no-insecure-url 136 await checkAlert("http://example.com/", { value: "example.com" }); 137 await checkAlert("data:text/html,<body>", { 138 l10nId: "common-dialog-title-null", 139 }); 140 141 let homeDir = Services.dirsvc.get("Home", Ci.nsIFile); 142 let fileURI = Services.io.newFileURI(homeDir).spec; 143 await checkAlert(fileURI, { value: "file://" }); 144 145 await checkAlert( 146 "about:config", 147 { l10nId: "common-dialog-title-system" }, 148 "chrome://branding/content/icon32.png" 149 ); 150 151 await checkBeforeunload(TEST_ROOT + "file_beforeunload_stop.html", { 152 value: "example.com", 153 }); 154 }); 155 156 add_task(async function test_check_auth() { 157 let server = new HttpServer(); 158 registerCleanupFunction(() => { 159 return new Promise(resolve => { 160 server.stop(() => { 161 server = null; 162 resolve(); 163 }); 164 }); 165 }); 166 167 function forbiddenHandler(meta, res) { 168 res.setStatusLine(meta.httpVersion, 401, "Unauthorized"); 169 res.setHeader("WWW-Authenticate", 'Basic realm="Realm"'); 170 } 171 function pageHandler(meta, res) { 172 res.setStatusLine(meta.httpVersion, 200, "OK"); 173 res.setHeader("Content-Type", "text/html"); 174 let body = "<html><body></body></html>"; 175 res.bodyOutputStream.write(body, body.length); 176 } 177 server.registerPathHandler("/forbidden", forbiddenHandler); 178 server.registerPathHandler("/page", pageHandler); 179 server.start(-1); 180 181 const HOST = `localhost:${server.identity.primaryPort}`; 182 // eslint-disable-next-line @microsoft/sdl/no-insecure-url 183 const AUTH_URI = `http://${HOST}/forbidden`; 184 185 // Try a simple load: 186 // Should be broken favicon since AUTH_URI's spec is http 187 await checkDialog( 188 "https://example.com/", 189 browser => BrowserTestUtils.startLoadingURIString(browser, AUTH_URI), 190 HOST, 191 BROKEN_FAVICON, 192 Ci.nsIPrompt.MODAL_TYPE_TAB 193 ); 194 195 let subframeLoad = function (browser, uri) { 196 return SpecialPowers.spawn(browser, [uri], frameUri => { 197 let f = content.document.createElement("iframe"); 198 f.src = frameUri; 199 content.document.body.appendChild(f); 200 }); 201 }; 202 203 // Try x-origin subframe: 204 await checkDialog( 205 // eslint-disable-next-line @microsoft/sdl/no-insecure-url 206 "http://example.org/1", 207 browser => subframeLoad(browser, AUTH_URI), 208 HOST, 209 BROKEN_FAVICON, 210 Ci.nsIPrompt.MODAL_TYPE_TAB 211 ); 212 });