From 857af4fe02a09ccf5333c5d6a5eca3139c3ad69e Mon Sep 17 00:00:00 2001 From: Gijs Kruitbosch Date: Tue, 29 Mar 2022 08:25:46 -0400 Subject: [PATCH] Bug 1743653 - tests for external protocol handler redirection, r=nika CLOSED TREE Differential Revision: https://phabricator.services.mozilla.com/D132528 --- .../exthandler/tests/mochitest/browser.ini | 3 + .../browser_protocol_ask_dialog_permission.js | 185 +++++++++++++++++- .../tests/mochitest/redirect_helper.sjs | 26 ++- .../tests/mochitest/script_redirect.html | 5 + 4 files changed, 212 insertions(+), 7 deletions(-) create mode 100644 uriloader/exthandler/tests/mochitest/script_redirect.html diff --git a/uriloader/exthandler/tests/mochitest/browser.ini b/uriloader/exthandler/tests/mochitest/browser.ini index fdb194fcda45..973fa8c03b00 100644 --- a/uriloader/exthandler/tests/mochitest/browser.ini +++ b/uriloader/exthandler/tests/mochitest/browser.ini @@ -97,6 +97,9 @@ support-files = support-files = redirect_helper.sjs [browser_protocol_ask_dialog_permission.js] +support-files = + redirect_helper.sjs + script_redirect.html [browser_protocolhandler_loop.js] [browser_remember_download_option.js] [browser_txt_download_save_as.js] diff --git a/uriloader/exthandler/tests/mochitest/browser_protocol_ask_dialog_permission.js b/uriloader/exthandler/tests/mochitest/browser_protocol_ask_dialog_permission.js index 8a9fc5876fbe..b8a115c0c729 100644 --- a/uriloader/exthandler/tests/mochitest/browser_protocol_ask_dialog_permission.js +++ b/uriloader/exthandler/tests/mochitest/browser_protocol_ask_dialog_permission.js @@ -7,6 +7,11 @@ let gHandlerService = Cc["@mozilla.org/uriloader/handler-service;1"].getService( Ci.nsIHandlerService ); +const ROOT_PATH = getRootDirectory(gTestPath).replace( + "chrome://mochitests/content/", + "" +); + // Testing multiple protocol / origin combinations takes long on debug. requestLongerTimeout(3); @@ -120,6 +125,9 @@ async function triggerOpenProto( useNullPrincipal = false, useExtensionPrincipal = false, omitTriggeringPrincipal = false, + useJSRedirect = false, + serverRedirect = "", + linkToRedirect = false, } = {} ) { let uri = `${scheme}://test`; @@ -172,6 +180,65 @@ async function triggerOpenProto( return; } + if (useJSRedirect) { + let innerParams = new URLSearchParams(); + innerParams.set("uri", uri); + let params = new URLSearchParams(); + params.set( + "uri", + "https://example.com/" + + ROOT_PATH + + "script_redirect.html?" + + innerParams.toString() + ); + uri = + "https://example.org/" + + ROOT_PATH + + "script_redirect.html?" + + params.toString(); + BrowserTestUtils.loadURI(browser, uri); + return; + } + + if (serverRedirect) { + let innerParams = new URLSearchParams(); + innerParams.set("uri", uri); + innerParams.set("redirectType", serverRedirect); + let params = new URLSearchParams(); + params.set( + "uri", + "https://example.com/" + + ROOT_PATH + + "redirect_helper.sjs?" + + innerParams.toString() + ); + uri = + "https://example.org/" + + ROOT_PATH + + "redirect_helper.sjs?" + + params.toString(); + BrowserTestUtils.loadURI(browser, uri); + return; + } + + if (linkToRedirect) { + let params = new URLSearchParams(); + params.set("uri", uri); + uri = + "https://example.com/" + + ROOT_PATH + + "redirect_helper.sjs?" + + params.toString(); + await ContentTask.spawn(browser, { uri }, args => { + let textLink = content.document.createElement("a"); + textLink.href = args.uri; + textLink.textContent = "click me"; + content.document.body.appendChild(textLink); + textLink.click(); + }); + return; + } + info("Loading uri: " + uri); browser.loadURI(uri, { triggeringPrincipal }); } @@ -229,6 +296,7 @@ async function testOpenProto( let { hasCheckbox, + checkboxOrigin, hasChangeApp, chooserIsNext, actionCheckbox, @@ -254,6 +322,7 @@ async function testOpenProto( await testCheckbox(dialogEl, dialogType, { hasCheckbox, actionCheckbox, + checkboxOrigin, }); // Check the button label depending on whether we would show the chooser @@ -311,7 +380,11 @@ async function testOpenProto( } // Clean up test extension if needed. - await testExtension?.unload(); + if (testExtension) { + await testExtension.unload(); + // Don't try to unload it again later! + testExtension = null; + } } /** @@ -330,7 +403,7 @@ async function testOpenProto( async function testCheckbox( dialogEl, dialogType, - { hasCheckbox, hasCheckboxState = false, actionCheckbox } + { hasCheckbox, hasCheckboxState = false, actionCheckbox, checkboxOrigin } ) { let checkbox = dialogEl.ownerDocument.getElementById("remember"); if (typeof hasCheckbox == "boolean") { @@ -358,6 +431,14 @@ async function testCheckbox( is(checkbox.checked, hasCheckboxState, "Dialog checkbox has correct state"); } + if (checkboxOrigin) { + let doc = dialogEl.ownerDocument; + let hostFromLabel = doc.l10n.getAttributes( + doc.getElementById("remember-label") + ).args.host; + is(hostFromLabel, checkboxOrigin, "Checkbox should be for correct domain."); + } + if (typeof actionCheckbox == "boolean") { checkbox.click(); } @@ -768,3 +849,103 @@ add_task(async function test_extension_principal() { }); }); }); + +/** + * Test that we use the redirect principal for the dialog when applicable. + */ +add_task(async function test_redirect_principal() { + let scheme = TEST_PROTOS[0]; + await BrowserTestUtils.withNewTab("about:blank", async browser => { + await testOpenProto(browser, scheme, { + loadOptions: { + serverRedirect: "location", + }, + permDialogOptions: { + checkboxOrigin: ORIGIN1, + chooserIsNext: true, + hasCheckbox: true, + actionConfirm: false, // Cancel dialog + }, + }); + }); +}); + +/** + * Test that we use the redirect principal for the dialog for refresh headers. + */ +add_task(async function test_redirect_principal() { + let scheme = TEST_PROTOS[0]; + await BrowserTestUtils.withNewTab("about:blank", async browser => { + await testOpenProto(browser, scheme, { + loadOptions: { + serverRedirect: "refresh", + }, + permDialogOptions: { + checkboxOrigin: ORIGIN1, + chooserIsNext: true, + hasCheckbox: true, + actionConfirm: false, // Cancel dialog + }, + }); + }); +}); + +/** + * Test that we use the redirect principal for the dialog for meta refreshes. + */ +add_task(async function test_redirect_principal() { + let scheme = TEST_PROTOS[0]; + await BrowserTestUtils.withNewTab("about:blank", async browser => { + await testOpenProto(browser, scheme, { + loadOptions: { + serverRedirect: "meta-refresh", + }, + permDialogOptions: { + checkboxOrigin: ORIGIN1, + chooserIsNext: true, + hasCheckbox: true, + actionConfirm: false, // Cancel dialog + }, + }); + }); +}); + +/** + * Test that we use the redirect principal for the dialog for JS redirects. + */ +add_task(async function test_redirect_principal_js() { + let scheme = TEST_PROTOS[0]; + await BrowserTestUtils.withNewTab("about:blank", async browser => { + await testOpenProto(browser, scheme, { + loadOptions: { + useJSRedirect: true, + }, + permDialogOptions: { + checkboxOrigin: ORIGIN1, + chooserIsNext: true, + hasCheckbox: true, + actionConfirm: false, // Cancel dialog + }, + }); + }); +}); + +/** + * Test that we use the redirect principal for the dialog for link clicks. + */ +add_task(async function test_redirect_principal_links() { + let scheme = TEST_PROTOS[0]; + await BrowserTestUtils.withNewTab("about:blank", async browser => { + await testOpenProto(browser, scheme, { + loadOptions: { + linkToRedirect: true, + }, + permDialogOptions: { + checkboxOrigin: ORIGIN1, + chooserIsNext: true, + hasCheckbox: true, + actionConfirm: false, // Cancel dialog + }, + }); + }); +}); diff --git a/uriloader/exthandler/tests/mochitest/redirect_helper.sjs b/uriloader/exthandler/tests/mochitest/redirect_helper.sjs index bf96b213eb71..5c1068bebbc2 100644 --- a/uriloader/exthandler/tests/mochitest/redirect_helper.sjs +++ b/uriloader/exthandler/tests/mochitest/redirect_helper.sjs @@ -6,9 +6,25 @@ Cu.importGlobalProperties(["URLSearchParams"]); function handleRequest(request, response) { - response.setStatusLine(request.httpVersion, 302, "Moved Temporarily"); - response.setHeader( - "Location", - new URLSearchParams(request.queryString).get("uri") - ); + let params = new URLSearchParams(request.queryString); + let uri = params.get("uri"); + let redirectType = params.get("redirectType") || "location"; + switch (redirectType) { + case "refresh": + response.setStatusLine(request.httpVersion, 200, "OK"); + response.setHeader("Refresh", "0; url=" + uri); + break; + + case "meta-refresh": + response.setStatusLine(request.httpVersion, 200, "OK"); + response.setHeader("Content-Type", "text/html"); + response.write(``); + break; + + case "location": + // fall through + default: + response.setStatusLine(request.httpVersion, 302, "Moved Temporarily"); + response.setHeader("Location", uri); + } } diff --git a/uriloader/exthandler/tests/mochitest/script_redirect.html b/uriloader/exthandler/tests/mochitest/script_redirect.html new file mode 100644 index 000000000000..31e0dc6a7eae --- /dev/null +++ b/uriloader/exthandler/tests/mochitest/script_redirect.html @@ -0,0 +1,5 @@ +