browser_net_html-preview.js (6629B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 /** 7 * Tests if different response content types are handled correctly. 8 */ 9 10 const httpServer = createTestHTTPServer(); 11 httpServer.registerContentType("html", "text/html"); 12 13 const BASE_URL = `http://localhost:${httpServer.identity.primaryPort}/`; 14 15 const REDIRECT_URL = BASE_URL + "redirect.html"; 16 17 // In all content previewed as HTML we ensure using proper html, head and body in order to 18 // prevent having them added by the <browser> when loaded as a preview. 19 function addBaseHtmlElements(body) { 20 return `<html><head></head><body>${body}</body></html>`; 21 } 22 23 const TEST_PAGES = { 24 // This page asserts we can redirect to another URL, even if JS happen to be executed 25 redirect: addBaseHtmlElements( 26 `Fetch 1<script>window.parent.location.href = "${REDIRECT_URL}";</script>` 27 ), 28 29 // #1 This page asserts that JS is disabled 30 js: addBaseHtmlElements( 31 `Fetch 2<script>document.write("JS activated")</script>` 32 ), 33 34 // #2 This page asserts that links and forms are disabled 35 forms: addBaseHtmlElements( 36 `Fetch 3<a href="${REDIRECT_URL}">link</a> -- <form action="${REDIRECT_URL}"><input type="submit"></form>` 37 ), 38 39 // #3 This page asserts responses with line breaks work 40 lineBreak: addBaseHtmlElements(` 41 <a href="#" id="link1">link1</a> 42 <a href="#" id="link2">link2</a> 43 `), 44 45 // #4 This page asserts that we apply inline styles 46 styles: addBaseHtmlElements(`<p style="color: red;">Hello World</p>`), 47 48 // #5 This page asserts that (multiple) Content-Security-Policy headers are applied 49 csp: addBaseHtmlElements(` 50 <base href="https://example.com/"> 51 52 <img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQIW2P4v5ThPwAG7wKklwQ/bwAAAABJRU5ErkJggg=="> 53 <iframe src="/foo.html"></iframe> 54 `), 55 }; 56 57 // Use fetch in order to prevent actually running this code in the test page 58 const TEST_HTML = addBaseHtmlElements( 59 `<div id="to-copy">HTML</div><script>` + 60 Object.keys(TEST_PAGES) 61 .map(name => `fetch("${BASE_URL}fetch-${name}.html");`) 62 .join("\n") + 63 `</script>` 64 ); 65 const TEST_URL = BASE_URL + "doc-html-preview.html"; 66 67 httpServer.registerPathHandler( 68 "/doc-html-preview.html", 69 (request, response) => { 70 response.setStatusLine(request.httpVersion, 200, "OK"); 71 response.write(TEST_HTML); 72 } 73 ); 74 75 for (const [name, content] of Object.entries(TEST_PAGES)) { 76 httpServer.registerPathHandler(`/fetch-${name}.html`, (request, response) => { 77 response.setStatusLine(request.httpVersion, 200, "OK"); 78 79 if (name === "csp") { 80 // Duplicate un-merged headers 81 response.setHeaderNoCheck("Content-Security-Policy", "img-src 'none'"); 82 response.setHeaderNoCheck("Content-Security-Policy", "base-uri 'self'"); 83 } 84 85 response.write(content); 86 }); 87 } 88 89 httpServer.registerPathHandler("/redirect.html", (request, response) => { 90 response.setStatusLine(request.httpVersion, 200, "OK"); 91 response.write("Redirected!"); 92 }); 93 94 add_task(async function () { 95 // Enable async events so that clicks on preview iframe's links are correctly 96 // going through the parent process which is meant to cancel any mousedown. 97 await pushPref("test.events.async.enabled", true); 98 99 const { monitor } = await initNetMonitor(TEST_URL, { requestCount: 3 }); 100 info("Starting test... "); 101 102 const { document, store, windowRequire } = monitor.panelWin; 103 const Actions = windowRequire("devtools/client/netmonitor/src/actions/index"); 104 105 store.dispatch(Actions.batchEnable(false)); 106 107 const onNetworkEvent = waitForNetworkEvents( 108 monitor, 109 1 + Object.keys(TEST_PAGES).length 110 ); 111 await reloadBrowser(); 112 await onNetworkEvent; 113 114 // The new lines are stripped when using outerHTML to retrieve HTML content of the preview iframe 115 await selectIndexAndWaitForHtmlView(0, "initial-page", TEST_HTML); 116 let index = 1; 117 for (const [name, content] of Object.entries(TEST_PAGES)) { 118 await selectIndexAndWaitForHtmlView(index, name, content); 119 index++; 120 } 121 122 await teardown(monitor); 123 124 async function selectIndexAndWaitForHtmlView( 125 index_, 126 name, 127 expectedHtmlPreview 128 ) { 129 info(`Select the request "${name}" #${index_}`); 130 const onResponseContent = monitor.panelWin.api.once( 131 TEST_EVENTS.RECEIVED_RESPONSE_CONTENT 132 ); 133 store.dispatch(Actions.selectRequestByIndex(index_)); 134 135 document.querySelector("#response-tab").click(); 136 137 const [browser] = await waitForDOM( 138 document, 139 "#response-panel .html-preview browser" 140 ); 141 142 await BrowserTestUtils.browserLoaded(browser); 143 144 info("Wait for response content to be loaded"); 145 await onResponseContent; 146 147 is( 148 browser.browsingContext.currentWindowGlobal.isInProcess, 149 false, 150 "The preview is loaded in a content process" 151 ); 152 153 await SpecialPowers.spawn( 154 browser.browsingContext, 155 [expectedHtmlPreview], 156 async function (expectedHtml) { 157 is( 158 content.document.documentElement.outerHTML, 159 expectedHtml, 160 "The text shown in the browser is incorrect for the html request." 161 ); 162 } 163 ); 164 165 if (name === "style") { 166 await SpecialPowers.spawn(browser.browsingContext, [], async function () { 167 const p = content.document.querySelector("p"); 168 const computed = content.window.getComputedStyle(p); 169 is( 170 computed.getPropertyValue("color"), 171 "rgb(255, 0, 0)", 172 "The inline style was not applied" 173 ); 174 }); 175 } 176 177 if (name == "csp") { 178 await SpecialPowers.spawn(browser.browsingContext, [], async function () { 179 is( 180 content.document.querySelector("img").complete, 181 false, 182 "img was blocked" 183 ); 184 is( 185 content.document.querySelector("iframe").src, 186 "/foo.html", 187 "URL of iframe was not changed by <base>" 188 ); 189 }); 190 } 191 192 // Only assert copy to clipboard on the first test page 193 if (name == "initial-page") { 194 await waitForClipboardPromise(async function () { 195 await SpecialPowers.spawn( 196 browser.browsingContext, 197 [], 198 async function () { 199 const elt = content.document.getElementById("to-copy"); 200 EventUtils.synthesizeMouseAtCenter(elt, { clickCount: 2 }, content); 201 await new Promise(r => 202 elt.addEventListener("dblclick", r, { once: true }) 203 ); 204 EventUtils.synthesizeKey("c", { accelKey: true }, content); 205 } 206 ); 207 }, "HTML"); 208 } 209 } 210 });