# HG changeset patch # Parent 2a04118c9379bd064886b33ed91931cf2fc23a88 Bug 1276048 - webextension tests diff --git a/browser/components/extensions/test/browser/browser-common.ini b/browser/components/extensions/test/browser/browser-common.ini --- a/browser/components/extensions/test/browser/browser-common.ini +++ b/browser/components/extensions/test/browser/browser-common.ini @@ -19,16 +19,17 @@ support-files = file_language_ja.html file_language_tlh.html file_dummy.html file_inspectedwindow_reload_target.sjs file_serviceWorker.html webNav_createdTarget.html webNav_createdTargetSource.html webNav_createdTargetSource_subframe.html + redirect.sjs serviceWorker.js searchSuggestionEngine.xml searchSuggestionEngine.sjs ../../../../../toolkit/components/extensions/test/mochitest/head_webrequest.js [browser_ext_browserAction_area.js] [browser_ext_browserAction_context.js] [browser_ext_browserAction_contextMenu.js] @@ -80,16 +81,18 @@ skip-if = debug || asan # Bug 1354681 [browser_ext_pageAction_popup_resize.js] [browser_ext_pageAction_simple.js] [browser_ext_pageAction_title.js] [browser_ext_popup_api_injection.js] [browser_ext_popup_background.js] [browser_ext_popup_corners.js] [browser_ext_popup_sendMessage.js] [browser_ext_popup_shutdown.js] +[browser_ext_redirect.js] +[browser_ext_redirect_chrome.js] [browser_ext_runtime_openOptionsPage.js] [browser_ext_runtime_openOptionsPage_uninstall.js] [browser_ext_runtime_setUninstallURL.js] [browser_ext_sessions_forgetClosedTab.js] [browser_ext_sessions_forgetClosedWindow.js] [browser_ext_sessions_getRecentlyClosed.js] [browser_ext_sessions_getRecentlyClosed_private.js] [browser_ext_sessions_getRecentlyClosed_tabs.js] diff --git a/browser/components/extensions/test/browser/browser_ext_redirect.js b/browser/components/extensions/test/browser/browser_ext_redirect.js new file mode 100644 --- /dev/null +++ b/browser/components/extensions/test/browser/browser_ext_redirect.js @@ -0,0 +1,144 @@ +"use strict"; + +const testExtension = { + manifest: { + "permissions": [ + "webRequest", + "webRequestBlocking", + "tabs", + "https://example.com/", + ], + }, + files: { + "finished.html": ` + + + + + + +

redirected!

+ + + `.trim(), + }, +}; + +function backgroundScript(expectFail) { + let exturi = browser.extension.getURL("/finished.html"); + let uri = "https://example.com/browser/browser/components/extensions/test/browser/redirect.sjs"; + let url = `${uri}?redirect_uri=${exturi}`; + + browser.webRequest.onBeforeRequest.addListener(details => { + browser.test.log(`onBeforeRequest url ${details.url}`); + }, {urls: [""]}, ["blocking"]); + browser.webRequest.onBeforeRedirect.addListener(details => { + browser.test.log(`onBeforeRedirect url from [${details.url}] to [${details.redirectUrl}]`); + }, {urls: [""]}); + browser.webRequest.onCompleted.addListener(details => { + browser.test.assertEq(exturi, details.url, "got correct url on redirect"); + }, {urls: [""]}); + browser.webRequest.onErrorOccurred.addListener(details => { + browser.test.fail(details.url, "moz-ext redirect failed"); + }, {urls: [""]}); + + browser.tabs.onUpdated.addListener((changedTabId, changed) => { + browser.test.log(`tabs.onUpdated ${changedTabId} ${JSON.stringify(changed)}`); + if (changed.status === "complete" && changed.url) { + if (expectFail) { + browser.test.assertEq(url, changed.url, "tab should not redirect to moz-extension"); + } else { + browser.test.assertEq(exturi, changed.url, "tab should redirect to moz-extension"); + } + browser.tabs.remove(changedTabId); + browser.test.sendMessage("done"); + } + }); + browser.tabs.create({url}); +} + +// Tests whether we can redirect to a moz-extension: url. This should result +// in a Corrupted Content Error page with an unchanged url. +add_task(function* test_extRedirect() { + testExtension.background = `(${backgroundScript})(true)`; + let extension = ExtensionTestUtils.loadExtension(testExtension); + + yield extension.startup(); + yield extension.awaitMessage("done"); + yield extension.unload(); +}); + +// Tests whether we can redirect to a moz-extension: url. This test adds the +// redirect destination to web_accessible_resources which should allow the +// redirect to occure. +add_task(function* test_extRedirect_accessible() { + testExtension.background = `(${backgroundScript})(false)`; + testExtension.manifest.web_accessible_resources = ["finished.html"]; + let extension = ExtensionTestUtils.loadExtension(testExtension); + + yield extension.startup(); + yield extension.awaitMessage("done"); + yield extension.unload(); +}); + +// Tests whether we can redirect to a moz-extension: url. +add_task(function* test_extRedirect_webRequest() { + let extension = ExtensionTestUtils.loadExtension({ + manifest: { + "permissions": [ + "tabs", + "webRequest", + "webRequestBlocking", + "", + ], + "web_accessible_resources": ["finished.html"], + }, + files: { + "finished.html": ` + + + + + + +

redirected!

+ + + `.trim(), + }, + background() { + let url = `http://example.com/browser/browser/components/extensions/test/browser/file_dummy.html?r=${Math.random()}`; + let exturi = browser.extension.getURL("finished.html"); + browser.webRequest.onBeforeRequest.addListener(details => { + browser.test.log(`onBeforeRequest url ${details.url}`); + if (details.url.includes("file_dummy.html")) { + browser.test.log(`... redirecting to ${exturi}`); + return {redirectUrl: exturi}; + } + }, {urls: [""]}, ["blocking"]); + browser.webRequest.onBeforeRedirect.addListener(details => { + browser.test.log(`onBeforeRedirect url from [${details.url}] to [${details.redirectUrl}]`); + }, {urls: [""]}); + browser.webRequest.onCompleted.addListener(details => { + browser.test.assertEq(exturi, details.url, "got correct url on redirect"); + }, {urls: [""]}); + browser.webRequest.onErrorOccurred.addListener(details => { + browser.test.fail(details.url, "moz-ext redirect failed"); + }, {urls: [""]}); + + browser.tabs.onUpdated.addListener((changedTabId, changed) => { + browser.test.log(`tabs.onUpdated ${changedTabId} ${JSON.stringify(changed)}`); + if (changed.status === "complete" && changed.url) { + browser.test.assertEq(exturi, changed.url, "tab should redirect to moz-extension"); + browser.tabs.remove(changedTabId); + browser.test.sendMessage("done"); + } + }); + browser.tabs.create({url}); + }, + }); + + yield extension.startup(); + yield extension.awaitMessage("done"); + yield extension.unload(); +}); diff --git a/browser/components/extensions/test/browser/browser_ext_redirect_chrome.js b/browser/components/extensions/test/browser/browser_ext_redirect_chrome.js new file mode 100644 --- /dev/null +++ b/browser/components/extensions/test/browser/browser_ext_redirect_chrome.js @@ -0,0 +1,112 @@ +"use strict"; + +// Tests whether we can redirect to a moz-extension: url. + +// nsIWebRequestListener is a nsIThreadRetargetableStreamListener that handles +// forwarding of nsIRequestObserver for JS consumers. It does nothing more +// than that. +let WebRequestListener = Components.Constructor("@mozilla.org/webextensions/webRequestListener;1", + "nsIWebRequestListener", "init"); + +function onStopListener(channel) { + info(`setup stream listener`); + return new Promise(resolve => { + new WebRequestListener({ + QueryInterface: XPCOMUtils.generateQI([Ci.nsIRequestObserver, + Ci.nsIStreamListener]), + onStartRequest: function(request, context) { + info(`setup stream onStartRequest ${request.URI.spec}`); + }, + onStopRequest(request, context, statusCode) { + info(`setup stream onStopRequest ${request.URI.spec}`); + resolve(request.URI.spec); + }, + }, channel); + channel.resume(); + }); +} + +function onModifyListener(originUrl, redirectToUrl) { + let obs = Services.obs; + return new Promise(resolve => { + obs.addObserver({ + observe: function(subject, topic, data) { + let channel = subject.QueryInterface(Ci.nsIHttpChannel); + if (channel.URI && channel.URI.spec != originUrl) { + return; + } + obs.removeObserver(this, "http-on-modify-request"); + channel.suspend(); + if (redirectToUrl) { + info(`redirecting channel to ${redirectToUrl}`); + channel.redirectTo(Services.io.newURI(redirectToUrl)); + } + onStopListener(channel).then(finalUrl => { + info(`onStop has completed ${finalUrl}`); + resolve(finalUrl); + }); + }, + }, "http-on-modify-request"); + }); +} + +let extension; +let redirectUrl; +add_task(function* startup() { + // This extension does nothing except provide us a public moz-extension url + // that we can land on. + extension = ExtensionTestUtils.loadExtension({ + manifest: { + "web_accessible_resources": ["finished.html"], + }, + files: { + "finished.html": ` + + + + + + +

redirected!

+ + + `.trim(), + }, + background() { + // send the extensions public uri to the test. + let exturi = browser.extension.getURL("finished.html"); + browser.test.sendMessage("redirectURI", exturi); + }, + }); + yield extension.startup(); + redirectUrl = yield extension.awaitMessage("redirectURI"); +}); + +function* redirection_test(url, redirectTo) { + // setup our observer + let watcher = onModifyListener(url, redirectTo); + // open a tab to the url and wait for watcher. + BrowserTestUtils.openNewForegroundTab(gBrowser, url); + let finalUrl = yield watcher; + is(finalUrl, redirectUrl, "redirect request is finished"); + // The tab never finished loading, presumably due to the redirect failure, + // so waiting on the tab here will hang. + yield BrowserTestUtils.removeTab(gBrowser.selectedTab); +} + +// This test makes a request against a server that redirects with a 302. +add_task(function* test_302_redirect_to_extension() { + let url = `https://example.com/browser/browser/components/extensions/test/browser/redirect.sjs?redirect_uri=${redirectUrl}`; + yield redirection_test(url); +}); + +// This test uses channel.redirectTo during http-on-modify to redirect to the +// moz-extension url. +add_task(function* test_channel_redirect_to_extension() { + let url = `http://example.com/browser/browser/components/extensions/test/browser/file_dummy.html?r=${Math.random()}`; + yield redirection_test(url, redirectUrl); +}); + +add_task(function* cleanup() { + yield extension.unload(); +}); diff --git a/browser/components/extensions/test/browser/redirect.sjs b/browser/components/extensions/test/browser/redirect.sjs new file mode 100644 --- /dev/null +++ b/browser/components/extensions/test/browser/redirect.sjs @@ -0,0 +1,16 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ + */ +Components.utils.importGlobalProperties(["URLSearchParams"]); + +function handleRequest(request, response) { + let params = new URLSearchParams(request.queryString); + if (params.has("no_redirect")) { + response.setStatusLine(request.httpVersion, 200, "OK"); + response.write("ok"); + } else { + response.setStatusLine(request.httpVersion, 302, "Moved Temporarily"); + dump("***** redirecting to ", params.get("redirect_uri")+"\n"); + response.setHeader("Location", params.get("redirect_uri")); + } +}