# HG changeset patch
# Parent dde2eb5ed71145b08a55cd089c2e7bb95fe29d4b
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,116 @@
+"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 uri [${request.URI && request.URI.spec}]`);
+ },
+ onStopRequest(request, context, statusCode) {
+ info(`setup stream onStopRequest uri [${request.URI && request.URI.spec}]`);
+ resolve(request.URI && 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;
+ if (!finalUrl) {
+ // non-e10, get the url off the tab
+ finalUrl = gBrowser.selectedTab.linkedBrowser.currentURI.spec;
+ }
+ 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"));
+ }
+}