summaryrefslogtreecommitdiffstats
path: root/uriloader/exthandler/tests/mochitest
diff options
context:
space:
mode:
Diffstat (limited to 'uriloader/exthandler/tests/mochitest')
-rw-r--r--uriloader/exthandler/tests/mochitest/browser.ini8
-rw-r--r--uriloader/exthandler/tests/mochitest/browser_download_always_ask_preferred_app.js19
-rw-r--r--uriloader/exthandler/tests/mochitest/browser_remember_download_option.js49
-rw-r--r--uriloader/exthandler/tests/mochitest/browser_web_protocol_handlers.js76
-rw-r--r--uriloader/exthandler/tests/mochitest/handlerApp.xhtml30
-rw-r--r--uriloader/exthandler/tests/mochitest/handlerApps.js110
-rw-r--r--uriloader/exthandler/tests/mochitest/head.js105
-rw-r--r--uriloader/exthandler/tests/mochitest/mochitest.ini10
-rw-r--r--uriloader/exthandler/tests/mochitest/protocolHandler.html16
-rw-r--r--uriloader/exthandler/tests/mochitest/test_handlerApps.xhtml12
-rw-r--r--uriloader/exthandler/tests/mochitest/test_unsafeBidiChars.xhtml77
-rw-r--r--uriloader/exthandler/tests/mochitest/unsafeBidiFileName.sjs14
-rw-r--r--uriloader/exthandler/tests/mochitest/unsafeBidi_chromeScript.js28
13 files changed, 554 insertions, 0 deletions
diff --git a/uriloader/exthandler/tests/mochitest/browser.ini b/uriloader/exthandler/tests/mochitest/browser.ini
new file mode 100644
index 000000000..9647dcf8c
--- /dev/null
+++ b/uriloader/exthandler/tests/mochitest/browser.ini
@@ -0,0 +1,8 @@
+[DEFAULT]
+head = head.js
+support-files =
+ protocolHandler.html
+
+[browser_download_always_ask_preferred_app.js]
+[browser_remember_download_option.js]
+[browser_web_protocol_handlers.js]
diff --git a/uriloader/exthandler/tests/mochitest/browser_download_always_ask_preferred_app.js b/uriloader/exthandler/tests/mochitest/browser_download_always_ask_preferred_app.js
new file mode 100644
index 000000000..40f7ef71e
--- /dev/null
+++ b/uriloader/exthandler/tests/mochitest/browser_download_always_ask_preferred_app.js
@@ -0,0 +1,19 @@
+add_task(function*() {
+ // Create mocked objects for test
+ let launcher = createMockedObjects(false);
+ // Open helper app dialog with mocked launcher
+ let dlg = yield* openHelperAppDialog(launcher);
+ let doc = dlg.document;
+ let location = doc.getElementById("source");
+ let expectedValue = launcher.source.prePath;
+ if (location.value != expectedValue) {
+ info("Waiting for dialog to be populated.");
+ yield BrowserTestUtils.waitForAttribute("value", location, expectedValue);
+ }
+ is(doc.getElementById("mode").selectedItem.id, "open", "Should be opening the file.");
+ ok(!dlg.document.getElementById("openHandler").selectedItem.hidden,
+ "Should not have selected a hidden item.");
+ let helperAppDialogHiddenPromise = BrowserTestUtils.windowClosed(dlg);
+ doc.documentElement.cancelDialog();
+ yield helperAppDialogHiddenPromise;
+});
diff --git a/uriloader/exthandler/tests/mochitest/browser_remember_download_option.js b/uriloader/exthandler/tests/mochitest/browser_remember_download_option.js
new file mode 100644
index 000000000..996e5ad69
--- /dev/null
+++ b/uriloader/exthandler/tests/mochitest/browser_remember_download_option.js
@@ -0,0 +1,49 @@
+add_task(function*() {
+ // create mocked objects
+ let launcher = createMockedObjects(true);
+
+ // open helper app dialog with mocked launcher
+ let dlg = yield* openHelperAppDialog(launcher);
+
+ let doc = dlg.document;
+
+ // Set remember choice
+ ok(!doc.getElementById("rememberChoice").checked,
+ "Remember choice checkbox should be not checked.");
+ doc.getElementById("rememberChoice").checked = true;
+
+ // Make sure the mock handler information is not in nsIHandlerService
+ ok(!gHandlerSvc.exists(launcher.MIMEInfo), "Should not be in nsIHandlerService.");
+
+ // close the dialog by pushing the ok button.
+ let dialogClosedPromise = BrowserTestUtils.windowClosed(dlg);
+ // Make sure the ok button is enabled, since the ok button might be disabled by
+ // EnableDelayHelper mechanism. Please refer the detailed
+ // https://dxr.mozilla.org/mozilla-central/source/toolkit/components/prompts/src/SharedPromptUtils.jsm#53
+ doc.documentElement.getButton("accept").disabled = false;
+ doc.documentElement.acceptDialog();
+ yield dialogClosedPromise;
+
+ // check the mocked handler information is saved in nsIHandlerService
+ ok(gHandlerSvc.exists(launcher.MIMEInfo), "Should be in nsIHandlerService.");
+ // check the extension.
+ var mimeType = gHandlerSvc.getTypeFromExtension("abc");
+ is(mimeType, launcher.MIMEInfo.type, "Got correct mime type.");
+ var handlerInfos = gHandlerSvc.enumerate();
+ while (handlerInfos.hasMoreElements()) {
+ let handlerInfo = handlerInfos.getNext().QueryInterface(Ci.nsIHandlerInfo);
+ if (handlerInfo.type == launcher.MIMEInfo.type) {
+ // check the alwaysAskBeforeHandling
+ ok(!handlerInfo.alwaysAskBeforeHandling,
+ "Should turn off the always ask.");
+ // check the preferredApplicationHandler
+ ok(handlerInfo.preferredApplicationHandler.equals(
+ launcher.MIMEInfo.preferredApplicationHandler),
+ "Should be equal to the mockedHandlerApp.");
+ // check the perferredAction
+ is(handlerInfo.preferredAction, launcher.MIMEInfo.preferredAction,
+ "Should be equal to Ci.nsIHandlerInfo.useHelperApp.");
+ break;
+ }
+ }
+});
diff --git a/uriloader/exthandler/tests/mochitest/browser_web_protocol_handlers.js b/uriloader/exthandler/tests/mochitest/browser_web_protocol_handlers.js
new file mode 100644
index 000000000..ac3e66258
--- /dev/null
+++ b/uriloader/exthandler/tests/mochitest/browser_web_protocol_handlers.js
@@ -0,0 +1,76 @@
+let testURL = "http://example.com/browser/" +
+ "uriloader/exthandler/tests/mochitest/protocolHandler.html";
+
+add_task(function*() {
+ // Load a page registering a protocol handler.
+ let browser = gBrowser.selectedBrowser;
+ browser.loadURI(testURL);
+ yield BrowserTestUtils.browserLoaded(browser, testURL);
+
+ // Register the protocol handler by clicking the notificationbar button.
+ let notificationValue = "Protocol Registration: testprotocol";
+ let getNotification = () =>
+ gBrowser.getNotificationBox().getNotificationWithValue(notificationValue);
+ yield BrowserTestUtils.waitForCondition(getNotification);
+ let notification = getNotification();
+ let button =
+ notification.getElementsByClassName("notification-button-default")[0];
+ ok(button, "got registration button");
+ button.click();
+
+ // Set the new handler as default.
+ const protoSvc = Cc["@mozilla.org/uriloader/external-protocol-service;1"].
+ getService(Ci.nsIExternalProtocolService);
+ let protoInfo = protoSvc.getProtocolHandlerInfo("testprotocol");
+ is(protoInfo.preferredAction, protoInfo.useHelperApp,
+ "using a helper application is the preferred action");
+ ok(!protoInfo.preferredApplicationHandler, "no preferred handler is set");
+ let handlers = protoInfo.possibleApplicationHandlers;
+ is(1, handlers.length, "only one handler registered for testprotocol");
+ let handler = handlers.queryElementAt(0, Ci.nsIHandlerApp);
+ ok(handler instanceof Ci.nsIWebHandlerApp, "the handler is a web handler");
+ is(handler.uriTemplate, "https://example.com/foobar?uri=%s",
+ "correct url template")
+ protoInfo.preferredApplicationHandler = handler;
+ protoInfo.alwaysAskBeforeHandling = false;
+ const handlerSvc = Cc["@mozilla.org/uriloader/handler-service;1"].
+ getService(Ci.nsIHandlerService);
+ handlerSvc.store(protoInfo);
+
+ // Middle-click a testprotocol link and check the new tab is correct
+ let link = "#link";
+ const expectedURL = "https://example.com/foobar?uri=testprotocol%3Atest";
+
+ let promiseTabOpened =
+ BrowserTestUtils.waitForNewTab(gBrowser, expectedURL);
+ yield BrowserTestUtils.synthesizeMouseAtCenter(link, {button: 1}, browser);
+ let tab = yield promiseTabOpened;
+ gBrowser.selectedTab = tab;
+ is(gURLBar.value, expectedURL,
+ "the expected URL is displayed in the location bar");
+ yield BrowserTestUtils.removeTab(tab);
+
+ // Shift-click the testprotocol link and check the new window.
+ let newWindowPromise = BrowserTestUtils.waitForNewWindow();
+ yield BrowserTestUtils.synthesizeMouseAtCenter(link, {shiftKey: true},
+ browser);
+ let win = yield newWindowPromise;
+ yield BrowserTestUtils.browserLoaded(win.gBrowser.selectedBrowser);
+ yield BrowserTestUtils.waitForCondition(() => win.gBrowser.currentURI.spec == expectedURL);
+ is(win.gURLBar.value, expectedURL,
+ "the expected URL is displayed in the location bar");
+ yield BrowserTestUtils.closeWindow(win);
+
+ // Click the testprotocol link and check the url in the current tab.
+ let loadPromise = BrowserTestUtils.browserLoaded(browser);
+ yield BrowserTestUtils.synthesizeMouseAtCenter(link, {}, browser);
+ yield loadPromise;
+ yield BrowserTestUtils.waitForCondition(() => gURLBar.value != testURL);
+ is(gURLBar.value, expectedURL,
+ "the expected URL is displayed in the location bar");
+
+ // Cleanup.
+ protoInfo.preferredApplicationHandler = null;
+ handlers.removeElementAt(0);
+ handlerSvc.store(protoInfo);
+});
diff --git a/uriloader/exthandler/tests/mochitest/handlerApp.xhtml b/uriloader/exthandler/tests/mochitest/handlerApp.xhtml
new file mode 100644
index 000000000..83ba0d1a5
--- /dev/null
+++ b/uriloader/exthandler/tests/mochitest/handlerApp.xhtml
@@ -0,0 +1,30 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Pseudo Web Handler App</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body onload="onLoad()">
+Pseudo Web Handler App
+
+<script class="testbody" type="text/javascript">
+<![CDATA[
+function onLoad() {
+
+ // if we have a window.opener, this must be the windowContext
+ // instance of this test. check that we got the URI right and clean up.
+ if (window.opener) {
+ window.opener.is(location.search,
+ "?uri=" + encodeURIComponent(window.opener.testURI),
+ "uri passed to web-handler app");
+ window.opener.SimpleTest.finish();
+ }
+
+ window.close();
+}
+]]>
+</script>
+
+</body>
+</html>
+
diff --git a/uriloader/exthandler/tests/mochitest/handlerApps.js b/uriloader/exthandler/tests/mochitest/handlerApps.js
new file mode 100644
index 000000000..597f9442d
--- /dev/null
+++ b/uriloader/exthandler/tests/mochitest/handlerApps.js
@@ -0,0 +1,110 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+// handlerApp.xhtml grabs this for verification purposes via window.opener
+var testURI = "webcal://127.0.0.1/rheeeeet.html";
+
+const Cc = SpecialPowers.Cc;
+
+function test() {
+
+ // set up the web handler object
+ var webHandler = Cc["@mozilla.org/uriloader/web-handler-app;1"].
+ createInstance(SpecialPowers.Ci.nsIWebHandlerApp);
+ webHandler.name = "Test Web Handler App";
+ webHandler.uriTemplate =
+ "http://mochi.test:8888/tests/uriloader/exthandler/tests/mochitest/" +
+ "handlerApp.xhtml?uri=%s";
+
+ // set up the uri to test with
+ var ioService = Cc["@mozilla.org/network/io-service;1"].
+ getService(SpecialPowers.Ci.nsIIOService);
+ var uri = ioService.newURI(testURI, null, null);
+
+ // create a window, and launch the handler in it
+ var newWindow = window.open("", "handlerWindow", "height=300,width=300");
+ var windowContext =
+ SpecialPowers.wrap(newWindow).QueryInterface(SpecialPowers.Ci.nsIInterfaceRequestor).
+ getInterface(SpecialPowers.Ci.nsIWebNavigation).
+ QueryInterface(SpecialPowers.Ci.nsIDocShell);
+
+ webHandler.launchWithURI(uri, windowContext);
+
+ // if we get this far without an exception, we've at least partly passed
+ // (remaining check in handlerApp.xhtml)
+ ok(true, "webHandler launchWithURI (existing window/tab) started");
+
+ // make the web browser launch in its own window/tab
+ webHandler.launchWithURI(uri);
+
+ // if we get this far without an exception, we've passed
+ ok(true, "webHandler launchWithURI (new window/tab) test started");
+
+ // set up the local handler object
+ var localHandler = Cc["@mozilla.org/uriloader/local-handler-app;1"].
+ createInstance(SpecialPowers.Ci.nsILocalHandlerApp);
+ localHandler.name = "Test Local Handler App";
+
+ // get a local app that we know will be there and do something sane
+ var osString = Cc["@mozilla.org/xre/app-info;1"].
+ getService(SpecialPowers.Ci.nsIXULRuntime).OS;
+
+ var dirSvc = Cc["@mozilla.org/file/directory_service;1"].
+ getService(SpecialPowers.Ci.nsIDirectoryServiceProvider);
+ if (osString == "WINNT") {
+ var windowsDir = dirSvc.getFile("WinD", {});
+ var exe = windowsDir.clone().QueryInterface(SpecialPowers.Ci.nsILocalFile);
+ exe.appendRelativePath("SYSTEM32\\HOSTNAME.EXE");
+
+ } else if (osString == "Darwin") {
+ var localAppsDir = dirSvc.getFile("LocApp", {});
+ exe = localAppsDir.clone();
+ exe.append("iCal.app"); // lingers after the tests finish, but this seems
+ // seems better than explicitly killing it, since
+ // developers who run the tests locally may well
+ // information in their running copy of iCal
+
+ if (navigator.userAgent.match(/ SeaMonkey\//)) {
+ // SeaMonkey tinderboxes don't like to have iCal lingering (and focused)
+ // on next test suite run(s).
+ todo(false, "On SeaMonkey, testing OS X as generic Unix. (Bug 749872)");
+
+ // assume a generic UNIX variant
+ exe = Cc["@mozilla.org/file/local;1"].
+ createInstance(SpecialPowers.Ci.nsILocalFile);
+ exe.initWithPath("/bin/echo");
+ }
+ } else {
+ // assume a generic UNIX variant
+ exe = Cc["@mozilla.org/file/local;1"].
+ createInstance(SpecialPowers.Ci.nsILocalFile);
+ exe.initWithPath("/bin/echo");
+ }
+
+ localHandler.executable = exe;
+ localHandler.launchWithURI(ioService.newURI(testURI, null, null));
+
+ // if we get this far without an exception, we've passed
+ ok(true, "localHandler launchWithURI test");
+
+ // if we ever decide that killing iCal is the right thing to do, change
+ // the if statement below from "NOTDarwin" to "Darwin"
+ if (osString == "NOTDarwin") {
+
+ var killall = Cc["@mozilla.org/file/local;1"].
+ createInstance(SpecialPowers.Ci.nsILocalFile);
+ killall.initWithPath("/usr/bin/killall");
+
+ var process = Cc["@mozilla.org/process/util;1"].
+ createInstance(SpecialPowers.Ci.nsIProcess);
+ process.init(killall);
+
+ var args = ['iCal'];
+ process.run(false, args, args.length);
+ }
+
+ SimpleTest.waitForExplicitFinish();
+}
+
+test();
diff --git a/uriloader/exthandler/tests/mochitest/head.js b/uriloader/exthandler/tests/mochitest/head.js
new file mode 100644
index 000000000..dad0493f8
--- /dev/null
+++ b/uriloader/exthandler/tests/mochitest/head.js
@@ -0,0 +1,105 @@
+Components.utils.import("resource://gre/modules/FileUtils.jsm");
+Components.utils.import("resource://gre/modules/Task.jsm");
+
+var gMimeSvc = Cc["@mozilla.org/mime;1"].getService(Ci.nsIMIMEService);
+var gHandlerSvc = Cc["@mozilla.org/uriloader/handler-service;1"].getService(Ci.nsIHandlerService);
+
+function createMockedHandlerApp() {
+ // Mock the executable
+ let mockedExecutable = FileUtils.getFile("TmpD", ["mockedExecutable"]);
+ if (!mockedExecutable.exists()) {
+ mockedExecutable.create(Ci.nsIFile.NORMAL_FILE_TYPE, 0o755);
+ }
+
+ // Mock the handler app
+ let mockedHandlerApp = Cc["@mozilla.org/uriloader/local-handler-app;1"]
+ .createInstance(Ci.nsILocalHandlerApp);
+ mockedHandlerApp.executable = mockedExecutable;
+ mockedHandlerApp.detailedDescription = "Mocked handler app";
+
+ registerCleanupFunction(function() {
+ // remove the mocked executable from disk.
+ if (mockedExecutable.exists()) {
+ mockedExecutable.remove(true);
+ }
+ });
+
+ return mockedHandlerApp;
+}
+
+function createMockedObjects(createHandlerApp) {
+ // Mock the mime info
+ let internalMockedMIME = gMimeSvc.getFromTypeAndExtension("text/x-test-handler", null);
+ internalMockedMIME.alwaysAskBeforeHandling = true;
+ internalMockedMIME.preferredAction = Ci.nsIHandlerInfo.useHelperApp;
+ internalMockedMIME.appendExtension("abc");
+ if (createHandlerApp) {
+ let mockedHandlerApp = createMockedHandlerApp();
+ internalMockedMIME.description = mockedHandlerApp.detailedDescription;
+ internalMockedMIME.possibleApplicationHandlers.appendElement(mockedHandlerApp, false);
+ internalMockedMIME.preferredApplicationHandler = mockedHandlerApp;
+ }
+
+ // Proxy for the mocked MIME info for faking the read-only attributes
+ let mockedMIME = new Proxy(internalMockedMIME, {
+ get: function (target, property) {
+ switch (property) {
+ case "hasDefaultHandler":
+ return true;
+ case "defaultDescription":
+ return "Default description";
+ default:
+ return target[property];
+ }
+ },
+ });
+
+ // Mock the launcher:
+ let mockedLauncher = {
+ MIMEInfo: mockedMIME,
+ source: Services.io.newURI("http://www.mozilla.org/", null, null),
+ suggestedFileName: "test_download_dialog.abc",
+ targetFileIsExecutable: false,
+ saveToDisk() {},
+ cancel() {},
+ launchWithApplication() {},
+ setWebProgressListener() {},
+ saveDestinationAvailable() {},
+ contentLength: 42,
+ targetFile: null, // never read
+ // PRTime is microseconds since epoch, Date.now() returns milliseconds:
+ timeDownloadStarted: Date.now() * 1000,
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsICancelable, Ci.nsIHelperAppLauncher])
+ };
+
+ registerCleanupFunction(function() {
+ // remove the mocked mime info from database.
+ let mockHandlerInfo = gMimeSvc.getFromTypeAndExtension("text/x-test-handler", null);
+ if (gHandlerSvc.exists(mockHandlerInfo)) {
+ gHandlerSvc.remove(mockHandlerInfo);
+ }
+ });
+
+ return mockedLauncher;
+}
+
+function* openHelperAppDialog(launcher) {
+ let helperAppDialog = Cc["@mozilla.org/helperapplauncherdialog;1"].
+ createInstance(Ci.nsIHelperAppLauncherDialog);
+
+ let helperAppDialogShownPromise = BrowserTestUtils.domWindowOpened();
+ try {
+ helperAppDialog.show(launcher, window, "foopy");
+ } catch (ex) {
+ ok(false, "Trying to show unknownContentType.xul failed with exception: " + ex);
+ Cu.reportError(ex);
+ }
+ let dlg = yield helperAppDialogShownPromise;
+
+ yield BrowserTestUtils.waitForEvent(dlg, "load", false);
+
+ is(dlg.location.href, "chrome://mozapps/content/downloads/unknownContentType.xul",
+ "Got correct dialog");
+
+ return dlg;
+}
diff --git a/uriloader/exthandler/tests/mochitest/mochitest.ini b/uriloader/exthandler/tests/mochitest/mochitest.ini
new file mode 100644
index 000000000..ae191dc7b
--- /dev/null
+++ b/uriloader/exthandler/tests/mochitest/mochitest.ini
@@ -0,0 +1,10 @@
+[DEFAULT]
+support-files =
+ handlerApp.xhtml
+ handlerApps.js
+ unsafeBidi_chromeScript.js
+ unsafeBidiFileName.sjs
+
+[test_handlerApps.xhtml]
+skip-if = (toolkit == 'android' || os == 'mac') || e10s # OS X: bug 786938
+[test_unsafeBidiChars.xhtml]
diff --git a/uriloader/exthandler/tests/mochitest/protocolHandler.html b/uriloader/exthandler/tests/mochitest/protocolHandler.html
new file mode 100644
index 000000000..5a929ba99
--- /dev/null
+++ b/uriloader/exthandler/tests/mochitest/protocolHandler.html
@@ -0,0 +1,16 @@
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>Protocol handler</title>
+ <meta content="text/html;charset=utf-8" http-equiv="Content-Type">
+ <meta content="utf-8" http-equiv="encoding">
+ </head>
+ <body>
+ <script type="text/javascript">
+ navigator.registerProtocolHandler("testprotocol",
+ "https://example.com/foobar?uri=%s",
+ "Test Protocol");
+ </script>
+ <a id="link" href="testprotocol:test">testprotocol link</a>
+ </body>
+</html>
diff --git a/uriloader/exthandler/tests/mochitest/test_handlerApps.xhtml b/uriloader/exthandler/tests/mochitest/test_handlerApps.xhtml
new file mode 100644
index 000000000..e5d73a232
--- /dev/null
+++ b/uriloader/exthandler/tests/mochitest/test_handlerApps.xhtml
@@ -0,0 +1,12 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Test for Handler Apps </title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="handlerApps.js"/>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+</body>
+</html>
+
diff --git a/uriloader/exthandler/tests/mochitest/test_unsafeBidiChars.xhtml b/uriloader/exthandler/tests/mochitest/test_unsafeBidiChars.xhtml
new file mode 100644
index 000000000..fafe0b4c5
--- /dev/null
+++ b/uriloader/exthandler/tests/mochitest/test_unsafeBidiChars.xhtml
@@ -0,0 +1,77 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+ <title>Test for Handling of unsafe bidi chars</title>
+ <script type="text/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
+ <script type="text/javascript" src="/tests/SimpleTest/SpawnTask.js"></script>
+ <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
+</head>
+<body>
+<p id="display"></p>
+<iframe id="test"></iframe>
+<script type="text/javascript">
+<![CDATA[
+
+var unsafeBidiChars = [
+ "\xe2\x80\xaa", // LRE
+ "\xe2\x80\xab", // RLE
+ "\xe2\x80\xac", // PDF
+ "\xe2\x80\xad", // LRO
+ "\xe2\x80\xae" // RLO
+];
+
+var tests = [
+ "{1}.test",
+ "{1}File.test",
+ "Fi{1}le.test",
+ "File{1}.test",
+ "File.{1}test",
+ "File.te{1}st",
+ "File.test{1}",
+ "File.{1}",
+];
+
+function replace(name, x) {
+ return name.replace(/\{1\}/, x);
+}
+
+function sanitize(name) {
+ return replace(name, '_');
+}
+
+add_task(function* () {
+ let url = SimpleTest.getTestFileURL("unsafeBidi_chromeScript.js");
+ let chromeScript = SpecialPowers.loadChromeScript(url);
+
+ for (let test of tests) {
+ for (let char of unsafeBidiChars) {
+ let promiseName = new Promise(function(resolve) {
+ chromeScript.addMessageListener("suggestedFileName",
+ function listener(data) {
+ chromeScript.removeMessageListener("suggestedFileName", listener);
+ resolve(data);
+ });
+ });
+ let name = replace(test, char);
+ let expected = sanitize(test);
+ document.getElementById("test").src =
+ "unsafeBidiFileName.sjs?name=" + encodeURIComponent(name);
+ is((yield promiseName), expected, "got the expected sanitized name");
+ }
+ }
+
+ let promise = new Promise(function(resolve) {
+ chromeScript.addMessageListener("unregistered", function listener() {
+ chromeScript.removeMessageListener("unregistered", listener);
+ resolve();
+ });
+ });
+ chromeScript.sendAsyncMessage("unregister");
+ yield promise;
+
+ chromeScript.destroy();
+});
+
+]]>
+</script>
+</body>
+</html>
diff --git a/uriloader/exthandler/tests/mochitest/unsafeBidiFileName.sjs b/uriloader/exthandler/tests/mochitest/unsafeBidiFileName.sjs
new file mode 100644
index 000000000..48301be5b
--- /dev/null
+++ b/uriloader/exthandler/tests/mochitest/unsafeBidiFileName.sjs
@@ -0,0 +1,14 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+function handleRequest(request, response) {
+ response.setStatusLine(request.httpVersion, 200, "OK");
+
+ if (!request.queryString.match(/^name=/))
+ return;
+ var name = decodeURIComponent(request.queryString.substring(5));
+
+ response.setHeader("Content-Type", "application/octet-stream; name=\"" + name + "\"");
+ response.setHeader("Content-Disposition", "inline; filename=\"" + name + "\"");
+}
diff --git a/uriloader/exthandler/tests/mochitest/unsafeBidi_chromeScript.js b/uriloader/exthandler/tests/mochitest/unsafeBidi_chromeScript.js
new file mode 100644
index 000000000..16c82d818
--- /dev/null
+++ b/uriloader/exthandler/tests/mochitest/unsafeBidi_chromeScript.js
@@ -0,0 +1,28 @@
+const { classes: Cc, interfaces: Ci, utils: Cu } = Components;
+
+Cu.import("resource://gre/modules/XPCOMUtils.jsm");
+
+const HELPERAPP_DIALOG_CONTRACT = "@mozilla.org/helperapplauncherdialog;1";
+const HELPERAPP_DIALOG_CID =
+ Components.ID(Cc[HELPERAPP_DIALOG_CONTRACT].number);
+
+const FAKE_CID = Cc["@mozilla.org/uuid-generator;1"].
+ getService(Ci.nsIUUIDGenerator).generateUUID();
+
+function HelperAppLauncherDialog() {}
+HelperAppLauncherDialog.prototype = {
+ show: function(aLauncher, aWindowContext, aReason) {
+ sendAsyncMessage("suggestedFileName", aLauncher.suggestedFileName);
+ },
+ QueryInterface: XPCOMUtils.generateQI([Ci.nsIHelperAppLauncherDialog])
+};
+
+var registrar = Components.manager.QueryInterface(Ci.nsIComponentRegistrar);
+registrar.registerFactory(FAKE_CID, "", HELPERAPP_DIALOG_CONTRACT,
+ XPCOMUtils._getFactory(HelperAppLauncherDialog));
+
+addMessageListener("unregister", function() {
+ registrar.registerFactory(HELPERAPP_DIALOG_CID, "",
+ HELPERAPP_DIALOG_CONTRACT, null);
+ sendAsyncMessage("unregistered");
+});