"use strict"; const { HttpServer } = ChromeUtils.importESModule( "resource://testing-common/httpd.sys.mjs" ); // nonlocal.example.com resolves to 127.0.0.1 via network.dns.native-is-localhost // but is NOT treated as a secure context (unlike localhost/127.0.0.1) const PUBLIC_SERVER_HOST = "nonlocal.example.com"; let gLocalServer; let gPublicServer; let gLocalServerPort; let gPublicServerPort; async function restorePermissions() { info("Restoring permissions"); Services.obs.notifyObservers(null, "testonly-reload-permissions-from-disk"); Services.perms.removeAll(); } add_setup(async function () { await SpecialPowers.pushPrefEnv({ set: [ ["permissions.manager.defaultsUrl", ""], ["network.lna.block_insecure_contexts", true], ["network.lna.blocking", true], ["network.http.rcwn.enabled", false], // Make nonlocal.example.com resolve to 127.0.0.1 ["network.dns.native-is-localhost", true], ], }); Services.obs.notifyObservers(null, "testonly-reload-permissions-from-disk"); // Start the "local" server (LNA target) on a random port gLocalServer = new HttpServer(); gLocalServer.start(-1); gLocalServerPort = gLocalServer.identity.primaryPort; info(`Local server started on port ${gLocalServerPort}`); registerLocalServerHandlers(gLocalServer); // Start the "public" server (serves the test page) on a random port gPublicServer = new HttpServer(); gPublicServer.start(-1); gPublicServerPort = gPublicServer.identity.primaryPort; // Add identity for nonlocal.example.com gPublicServer.identity.add("http", PUBLIC_SERVER_HOST, gPublicServerPort); info(`Public server started on port ${gPublicServerPort}`); registerPublicServerHandlers(gPublicServer); registerCleanupFunction(async () => { await restorePermissions(); await new Promise(resolve => { gLocalServer.stop(resolve); }); await new Promise(resolve => { gPublicServer.stop(resolve); }); }); }); function registerLocalServerHandlers(server) { server.registerPathHandler("/", (request, response) => { response.setHeader("Access-Control-Allow-Origin", "*", false); response.setHeader("Content-Type", "text/plain", false); response.setStatusLine(request.httpVersion, 200, "OK"); response.write("hello from localhost"); }); } function registerPublicServerHandlers(server) { server.registerPathHandler("/test.html", (request, response) => { const params = new URLSearchParams(request.queryString); const testType = params.get("test"); const rand = params.get("rand"); const targetURL = `http://localhost:${gLocalServerPort}/?type=${testType}&rand=${rand}`; response.setHeader("Content-Type", "text/html", false); response.setStatusLine(request.httpVersion, 200, "OK"); let script; switch (testType) { case "fetch": script = ` fetch("${targetURL}") .then(response => console.log("fetch succeeded:", response)) .catch(error => console.log("fetch failed:", error)); `; break; case "xhr": script = ` const xhr = new XMLHttpRequest(); xhr.open("GET", "${targetURL}"); xhr.onload = () => console.log("xhr succeeded"); xhr.onerror = () => console.log("xhr failed"); xhr.send(); `; break; case "img": script = ` const img = document.createElement("img"); img.src = "${targetURL}"; img.onload = () => console.log("img loaded"); img.onerror = () => console.log("img failed"); document.body.appendChild(img); `; break; default: script = `console.error("Unknown test type: ${testType}");`; } response.write(`