diff options
Diffstat (limited to '')
7 files changed, 340 insertions, 0 deletions
diff --git a/devtools/shared/security/tests/chrome/chrome.ini b/devtools/shared/security/tests/chrome/chrome.ini new file mode 100644 index 0000000000..5812511032 --- /dev/null +++ b/devtools/shared/security/tests/chrome/chrome.ini @@ -0,0 +1,4 @@ +[DEFAULT] +tags = devtools + +[test_websocket-transport.html] diff --git a/devtools/shared/security/tests/chrome/test_websocket-transport.html b/devtools/shared/security/tests/chrome/test_websocket-transport.html new file mode 100644 index 0000000000..8e4652fb1d --- /dev/null +++ b/devtools/shared/security/tests/chrome/test_websocket-transport.html @@ -0,0 +1,72 @@ +<!DOCTYPE HTML> +<html> +<head> + <meta charset="utf-8"> + <title>Test the WebSocket debugger transport</title> + <script src="chrome://mochikit/content/tests/SimpleTest/SimpleTest.js"></script> + <link rel="stylesheet" type="text/css" href="chrome://mochikit/content/tests/SimpleTest/test.css"> +</head> +<body> +<script> +"use strict"; + +window.onload = function() { + const {require} = ChromeUtils.importESModule("resource://devtools/shared/loader/Loader.sys.mjs"); + // eslint-disable-next-line mozilla/reject-some-requires + const {DevToolsClient} = require("devtools/client/devtools-client"); + const {DevToolsServer} = require("devtools/server/devtools-server"); + const { SocketListener } = require("devtools/shared/security/socket"); + + Services.prefs.setBoolPref("devtools.debugger.remote-enabled", true); + Services.prefs.setBoolPref("devtools.debugger.prompt-connection", false); + + SimpleTest.registerCleanupFunction(() => { + Services.prefs.clearUserPref("devtools.debugger.remote-enabled"); + Services.prefs.clearUserPref("devtools.debugger.prompt-connection"); + }); + + add_task(async function() { + DevToolsServer.init(); + DevToolsServer.registerAllActors(); + + is(DevToolsServer.listeningSockets, 0, "0 listening sockets"); + + const socketOptions = { + portOrPath: -1, + webSocket: true, + }; + const listener = new SocketListener(DevToolsServer, socketOptions); + ok(listener, "Socket listener created"); + await listener.open(); + is(DevToolsServer.listeningSockets, 1, "1 listening socket"); + + const transport = await DevToolsClient.socketConnect({ + host: "127.0.0.1", + port: listener.port, + webSocket: true, + }); + ok(transport, "Client transport created"); + + const client = new DevToolsClient(transport); + const onUnexpectedClose = () => { + ok(false, "Closed unexpectedly"); + }; + client.on("closed", onUnexpectedClose); + + await client.connect(); + + // Send a message the server + const reply = await client.mainRoot.getRoot(); + is(reply.from, "root", "Got expected response"); + + client.off("closed", onUnexpectedClose); + transport.close(); + listener.close(); + is(DevToolsServer.listeningSockets, 0, "0 listening sockets"); + + DevToolsServer.destroy(); + }); +}; +</script> +</body> +</html> diff --git a/devtools/shared/security/tests/xpcshell/.eslintrc.js b/devtools/shared/security/tests/xpcshell/.eslintrc.js new file mode 100644 index 0000000000..8611c174f5 --- /dev/null +++ b/devtools/shared/security/tests/xpcshell/.eslintrc.js @@ -0,0 +1,6 @@ +"use strict"; + +module.exports = { + // Extend from the common devtools xpcshell eslintrc config. + extends: "../../../../.eslintrc.xpcshell.js", +}; diff --git a/devtools/shared/security/tests/xpcshell/head_dbg.js b/devtools/shared/security/tests/xpcshell/head_dbg.js new file mode 100644 index 0000000000..30359e6ac3 --- /dev/null +++ b/devtools/shared/security/tests/xpcshell/head_dbg.js @@ -0,0 +1,95 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +/* exported DevToolsClient, initTestDevToolsServer */ + +const { loader, require } = ChromeUtils.importESModule( + "resource://devtools/shared/loader/Loader.sys.mjs" +); +const xpcInspector = require("xpcInspector"); +const { + DevToolsServer, +} = require("resource://devtools/server/devtools-server.js"); +const { + DevToolsClient, +} = require("resource://devtools/client/devtools-client.js"); +// We need to require lazily since will be crashed if we load SocketListener too early +// in xpc shell test due to SocketListener loads PSM module. +loader.lazyRequireGetter( + this, + "SocketListener", + "resource://devtools/shared/security/socket.js", + true +); + +// We do not want to log packets by default, because in some tests, +// we can be sending large amounts of data. The test harness has +// trouble dealing with logging all the data, and we end up with +// intermittent time outs (e.g. bug 775924). +// Services.prefs.setBoolPref("devtools.debugger.log", true); +// Services.prefs.setBoolPref("devtools.debugger.log.verbose", true); +// Enable remote debugging for the relevant tests. +Services.prefs.setBoolPref("devtools.debugger.remote-enabled", true); + +// Convert an nsIScriptError 'logLevel' value into an appropriate string. +function scriptErrorLogLevel(message) { + switch (message.logLevel) { + case Ci.nsIConsoleMessage.info: + return "info"; + case Ci.nsIConsoleMessage.warn: + return "warning"; + default: + Assert.equal(message.logLevel, Ci.nsIConsoleMessage.error); + return "error"; + } +} + +// Register a console listener, so console messages don't just disappear +// into the ether. +var listener = { + observe(message) { + let string; + try { + message.QueryInterface(Ci.nsIScriptError); + dump( + message.sourceName + + ":" + + message.lineNumber + + ": " + + scriptErrorLogLevel(message) + + ": " + + message.errorMessage + + "\n" + ); + string = message.errorMessage; + } catch (ex) { + // Be a little paranoid with message, as the whole goal here is to lose + // no information. + try { + string = "" + message.message; + } catch (e) { + string = "<error converting error message to string>"; + } + } + + // Make sure we exit all nested event loops so that the test can finish. + while (xpcInspector.eventLoopNestLevel > 0) { + xpcInspector.exitNestedEventLoop(); + } + + info("head_dbg.js got console message: " + string + "\n"); + }, +}; + +Services.console.registerListener(listener); + +/** + * Initialize the testing devtools server. + */ +function initTestDevToolsServer() { + const { createRootActor } = require("xpcshell-test/testactors"); + DevToolsServer.setRootActor(createRootActor); + DevToolsServer.init(); +} diff --git a/devtools/shared/security/tests/xpcshell/test_devtools_socket_status.js b/devtools/shared/security/tests/xpcshell/test_devtools_socket_status.js new file mode 100644 index 0000000000..2e41583b05 --- /dev/null +++ b/devtools/shared/security/tests/xpcshell/test_devtools_socket_status.js @@ -0,0 +1,137 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ + +"use strict"; + +const { + useDistinctSystemPrincipalLoader, + releaseDistinctSystemPrincipalLoader, +} = ChromeUtils.importESModule( + "resource://devtools/shared/loader/DistinctSystemPrincipalLoader.sys.mjs" +); + +const { DevToolsSocketStatus } = ChromeUtils.importESModule( + "resource://devtools/shared/security/DevToolsSocketStatus.sys.mjs" +); + +add_task(async function () { + Services.prefs.setBoolPref("devtools.debugger.remote-enabled", true); + Services.prefs.setBoolPref("devtools.debugger.prompt-connection", false); + + info("Without any server started, all states should be set to false"); + checkSocketStatus(false, false); + + info("Start a first server, expect all states to change to true"); + const server = await setupDevToolsServer({ fromBrowserToolbox: false }); + checkSocketStatus(true, true); + + info("Start another server, expect all states to remain true"); + const otherServer = await setupDevToolsServer({ fromBrowserToolbox: false }); + checkSocketStatus(true, true); + + info("Shutdown one of the servers, expect all states to remain true"); + teardownDevToolsServer(otherServer); + checkSocketStatus(true, true); + + info("Shutdown the other server, expect all states to change to false"); + teardownDevToolsServer(server); + checkSocketStatus(false, false); + + info( + "Start a 'browser toolbox' server, expect only the 'include' state to become true" + ); + const browserToolboxServer = await setupDevToolsServer({ + fromBrowserToolbox: true, + }); + checkSocketStatus(true, false); + + info( + "Shutdown the 'browser toolbox' server, expect all states to become false" + ); + teardownDevToolsServer(browserToolboxServer); + checkSocketStatus(false, false); + + Services.prefs.clearUserPref("devtools.debugger.remote-enabled"); + Services.prefs.clearUserPref("devtools.debugger.prompt-connection"); +}); + +function checkSocketStatus(expectedExcludeFalse, expectedExcludeTrue) { + const openedDefault = DevToolsSocketStatus.hasSocketOpened(); + const openedExcludeFalse = DevToolsSocketStatus.hasSocketOpened({ + excludeBrowserToolboxSockets: false, + }); + const openedExcludeTrue = DevToolsSocketStatus.hasSocketOpened({ + excludeBrowserToolboxSockets: true, + }); + + equal( + openedDefault, + openedExcludeFalse, + "DevToolsSocketStatus.hasSocketOpened should default to excludeBrowserToolboxSockets=false" + ); + equal( + openedExcludeFalse, + expectedExcludeFalse, + "DevToolsSocketStatus matches the expectation for excludeBrowserToolboxSockets=false" + ); + equal( + openedExcludeTrue, + expectedExcludeTrue, + "DevToolsSocketStatus matches the expectation for excludeBrowserToolboxSockets=true" + ); +} + +async function setupDevToolsServer({ fromBrowserToolbox }) { + info("Use the dedicated system principal loader for the DevToolsServer."); + const requester = {}; + const loader = useDistinctSystemPrincipalLoader(requester); + + const { DevToolsServer } = loader.require( + "resource://devtools/server/devtools-server.js" + ); + + DevToolsServer.init(); + DevToolsServer.registerAllActors(); + DevToolsServer.allowChromeProcess = true; + const socketOptions = { + fromBrowserToolbox, + // Pass -1 to automatically choose an available port + portOrPath: -1, + }; + + const listener = new SocketListener(DevToolsServer, socketOptions); + ok(listener, "Socket listener created"); + + // Note that useDistinctSystemPrincipalLoader will lead to reuse the same + // loader if we are creating several servers in a row. The DevToolsServer + // singleton might already have sockets opened. + const listeningSockets = DevToolsServer.listeningSockets; + await listener.open(); + equal( + DevToolsServer.listeningSockets, + listeningSockets + 1, + "A new listening socket was created" + ); + + return { DevToolsServer, listener, requester }; +} + +function teardownDevToolsServer({ DevToolsServer, listener, requester }) { + info("Close the listener socket"); + const listeningSockets = DevToolsServer.listeningSockets; + listener.close(); + equal( + DevToolsServer.listeningSockets, + listeningSockets - 1, + "A listening socket was closed" + ); + + if (DevToolsServer.listeningSockets == 0) { + info("Destroy the temporary devtools server"); + DevToolsServer.destroy(); + } + + if (requester) { + releaseDistinctSystemPrincipalLoader(requester); + } +} diff --git a/devtools/shared/security/tests/xpcshell/testactors.js b/devtools/shared/security/tests/xpcshell/testactors.js new file mode 100644 index 0000000000..0a35f05287 --- /dev/null +++ b/devtools/shared/security/tests/xpcshell/testactors.js @@ -0,0 +1,16 @@ +/* Any copyright is dedicated to the Public Domain. + http://creativecommons.org/publicdomain/zero/1.0/ */ +"use strict"; + +const { RootActor } = require("resource://devtools/server/actors/root.js"); +const { + ActorRegistry, +} = require("resource://devtools/server/actors/utils/actor-registry.js"); + +exports.createRootActor = function createRootActor(connection) { + const root = new RootActor(connection, { + globalActorFactories: ActorRegistry.globalActorFactories, + }); + root.applicationType = "xpcshell-tests"; + return root; +}; diff --git a/devtools/shared/security/tests/xpcshell/xpcshell.ini b/devtools/shared/security/tests/xpcshell/xpcshell.ini new file mode 100644 index 0000000000..1981d8206d --- /dev/null +++ b/devtools/shared/security/tests/xpcshell/xpcshell.ini @@ -0,0 +1,10 @@ +[DEFAULT] +tags = devtools +head = head_dbg.js +skip-if = toolkit == 'android' +firefox-appdir = browser + +support-files= + testactors.js + +[test_devtools_socket_status.js] |