Mypal68/toolkit/components/extensions/test/mochitest/test_ext_protocolHandlers.html
2025-04-19 19:15:41 +03:00

353 lines
11 KiB
HTML

<!DOCTYPE HTML>
<html>
<head>
<meta charset="utf-8">
<title>Test for protocol handlers</title>
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<script src="/tests/SimpleTest/ExtensionTestUtils.js"></script>
<script type="text/javascript" src="head.js"></script>
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
</head>
<body>
<script type="text/javascript">
"use strict";
/* eslint-disable mozilla/balanced-listeners */
/* global addMessageListener, sendAsyncMessage */
function protocolChromeScript() {
addMessageListener("setup", () => {
let data = {};
const protoSvc = Cc["@mozilla.org/uriloader/external-protocol-service;1"]
.getService(Ci.nsIExternalProtocolService);
let protoInfo = protoSvc.getProtocolHandlerInfo("ext+foo");
data.preferredAction = protoInfo.preferredAction === protoInfo.useHelperApp;
let handlers = protoInfo.possibleApplicationHandlers;
data.handlers = handlers.length;
let handler = handlers.queryElementAt(0, Ci.nsIHandlerApp);
data.isWebHandler = handler instanceof Ci.nsIWebHandlerApp;
data.uriTemplate = handler.uriTemplate;
// ext+ protocols should be set as default when there is only one
data.preferredApplicationHandler = protoInfo.preferredApplicationHandler == handler;
data.alwaysAskBeforeHandling = protoInfo.alwaysAskBeforeHandling;
const handlerSvc = Cc["@mozilla.org/uriloader/handler-service;1"]
.getService(Ci.nsIHandlerService);
handlerSvc.store(protoInfo);
sendAsyncMessage("handlerData", data);
});
}
add_task(async function test_protocolHandler() {
await SpecialPowers.pushPrefEnv({set: [
["extensions.allowPrivateBrowsingByDefault", false],
]});
let extensionData = {
manifest: {
"protocol_handlers": [
{
"protocol": "ext+foo",
"name": "a foo protocol handler",
"uriTemplate": "foo.html?val=%s",
},
],
},
background() {
browser.test.onMessage.addListener(async (msg, arg) => {
if (msg == "open") {
let tab = await browser.tabs.create({url: arg});
browser.test.sendMessage("opened", tab.id);
} else if (msg == "close") {
await browser.tabs.remove(arg);
browser.test.sendMessage("closed");
}
});
browser.test.sendMessage("test-url", browser.runtime.getURL("foo.html"));
},
files: {
"foo.js": function() {
browser.test.sendMessage("test-query", location.search);
},
"foo.html": `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="foo.js"><\/script>
</head>
</html>`,
},
};
let pb_extension = ExtensionTestUtils.loadExtension({
background() {
browser.test.onMessage.addListener(async (msg, arg) => {
if (msg == "open") {
let tab = await browser.windows.create({url: arg, incognito: true});
browser.test.sendMessage("opened", tab.id);
} else if (msg == "close") {
await browser.windows.remove(arg);
browser.test.sendMessage("closed");
}
});
},
incognitoOverride: "spanning",
});
await pb_extension.startup();
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
let handlerUrl = await extension.awaitMessage("test-url");
// Ensure that the protocol handler is configured, and set it as default to
// bypass the dialog.
let chromeScript = SpecialPowers.loadChromeScript(protocolChromeScript);
let msg = chromeScript.promiseOneMessage("handlerData");
chromeScript.sendAsyncMessage("setup");
let data = await msg;
ok(data.preferredAction, "using a helper application is the preferred action");
ok(data.preferredApplicationHandler, "handler was set as default handler");
is(data.handlers, 1, "one handler is set");
ok(!data.alwaysAskBeforeHandling, "will not show dialog");
ok(data.isWebHandler, "the handler is a web handler");
is(data.uriTemplate, `${handlerUrl}?val=%s`, "correct url template");
chromeScript.destroy();
extension.sendMessage("open", "ext+foo:test");
let id = await extension.awaitMessage("opened");
let query = await extension.awaitMessage("test-query");
is(query, "?val=ext%2Bfoo%3Atest", "test query ok");
extension.sendMessage("close", id);
await extension.awaitMessage("closed");
// Test the protocol in a private window, watch for the
// console error.
consoleMonitor.start([{message: /NS_ERROR_FILE_NOT_FOUND/}]);
// Expect the chooser window to be open, close it.
chromeScript = SpecialPowers.loadChromeScript(async () => {
const {BrowserTestUtils} = ChromeUtils.import("resource://testing-common/BrowserTestUtils.jsm");
let window = await BrowserTestUtils.domWindowOpened(undefined, win => {
return BrowserTestUtils.waitForEvent(win, "load", false, event => {
let win = event.target.defaultView;
return !!win.document.querySelector("dialog#handling");
});
});
let entry = window.document.getElementById("items").firstChild;
sendAsyncMessage("handling", {name: entry.getAttribute("name"), disabled: entry.disabled});
window.close();
});
let testData = chromeScript.promiseOneMessage("handling");
pb_extension.sendMessage("open", "ext+foo:test");
id = await pb_extension.awaitMessage("opened");
await consoleMonitor.finished();
let entry = await testData;
is(entry.name, "a foo protocol handler", "entry is correct");
ok(entry.disabled, "handler is disabled");
pb_extension.sendMessage("close", id);
await pb_extension.awaitMessage("closed");
await pb_extension.unload();
// Shutdown the addon, then ensure the protocol was removed.
await extension.unload();
chromeScript = SpecialPowers.loadChromeScript(() => {
addMessageListener("setup", () => {
const protoSvc = Cc["@mozilla.org/uriloader/external-protocol-service;1"]
.getService(Ci.nsIExternalProtocolService);
let protoInfo = protoSvc.getProtocolHandlerInfo("ext+foo");
sendAsyncMessage("preferredApplicationHandler", !protoInfo.preferredApplicationHandler);
let handlers = protoInfo.possibleApplicationHandlers;
sendAsyncMessage("handlerData", {
preferredApplicationHandler: !protoInfo.preferredApplicationHandler,
handlers: handlers.length,
});
});
});
msg = chromeScript.promiseOneMessage("handlerData");
chromeScript.sendAsyncMessage("setup");
data = await msg;
ok(data.preferredApplicationHandler, "no preferred handler is set");
is(data.handlers, 0, "no handler is set");
chromeScript.destroy();
});
add_task(async function test_protocolHandler_two() {
let extensionData = {
manifest: {
"protocol_handlers": [
{
"protocol": "ext+foo",
"name": "a foo protocol handler",
"uriTemplate": "foo.html?val=%s",
},
{
"protocol": "ext+foo",
"name": "another foo protocol handler",
"uriTemplate": "foo2.html?val=%s",
},
],
},
};
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
// Ensure that the protocol handler is configured, and set it as default,
// but because there are two handlers, the dialog is not bypassed. We
// don't test the actual dialog ui, it's been here forever and works based
// on the alwaysAskBeforeHandling value.
let chromeScript = SpecialPowers.loadChromeScript(protocolChromeScript);
let msg = chromeScript.promiseOneMessage("handlerData");
chromeScript.sendAsyncMessage("setup");
let data = await msg;
ok(data.preferredAction, "using a helper application is the preferred action");
ok(data.preferredApplicationHandler, "preferred handler is set");
is(data.handlers, 2, "two handlers are set");
ok(data.alwaysAskBeforeHandling, "will show dialog");
ok(data.isWebHandler, "the handler is a web handler");
chromeScript.destroy();
await extension.unload();
});
add_task(async function test_protocolHandler_https_target() {
let extensionData = {
manifest: {
"protocol_handlers": [
{
"protocol": "ext+foo",
"name": "http target",
"uriTemplate": "https://example.com/foo.html?val=%s",
},
],
},
};
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
ok(true, "https uriTemplate target works");
await extension.unload();
});
add_task(async function test_protocolHandler_http_target() {
let extensionData = {
manifest: {
"protocol_handlers": [
{
"protocol": "ext+foo",
"name": "http target",
"uriTemplate": "http://example.com/foo.html?val=%s",
},
],
},
};
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
ok(true, "http uriTemplate target works");
await extension.unload();
});
add_task(async function test_protocolHandler_restricted_protocol() {
let extensionData = {
manifest: {
"protocol_handlers": [
{
"protocol": "http",
"name": "take over the http protocol",
"uriTemplate": "http.html?val=%s",
},
],
},
};
consoleMonitor.start([{message: /processing protocol_handlers\.0\.protocol/}]);
let extension = ExtensionTestUtils.loadExtension(extensionData);
await Assert.rejects(extension.startup(),
/startup failed/,
"unable to register restricted handler protocol");
await consoleMonitor.finished();
});
add_task(async function test_protocolHandler_restricted_uriTemplate() {
let extensionData = {
manifest: {
"protocol_handlers": [
{
"protocol": "ext+foo",
"name": "take over the http protocol",
"uriTemplate": "ftp://example.com/file.txt",
},
],
},
};
consoleMonitor.start([{message: /processing protocol_handlers\.0\.uriTemplate/}]);
let extension = ExtensionTestUtils.loadExtension(extensionData);
await Assert.rejects(extension.startup(),
/startup failed/,
"unable to register restricted handler uriTemplate");
await consoleMonitor.finished();
});
add_task(async function test_protocolHandler_duplicate() {
let extensionData = {
manifest: {
"protocol_handlers": [
{
"protocol": "ext+foo",
"name": "foo protocol",
"uriTemplate": "foo.html?val=%s",
},
{
"protocol": "ext+foo",
"name": "foo protocol",
"uriTemplate": "foo.html?val=%s",
},
],
},
};
let extension = ExtensionTestUtils.loadExtension(extensionData);
await extension.startup();
// Get the count of handlers installed.
let chromeScript = SpecialPowers.loadChromeScript(() => {
addMessageListener("setup", () => {
const protoSvc = Cc["@mozilla.org/uriloader/external-protocol-service;1"]
.getService(Ci.nsIExternalProtocolService);
let protoInfo = protoSvc.getProtocolHandlerInfo("ext+foo");
let handlers = protoInfo.possibleApplicationHandlers;
sendAsyncMessage("handlerData", handlers.length);
});
});
let msg = chromeScript.promiseOneMessage("handlerData");
chromeScript.sendAsyncMessage("setup");
let data = await msg;
is(data, 1, "cannot re-register the same handler config");
chromeScript.destroy();
await extension.unload();
});
</script>
</body>
</html>