commit 18ae2eefe6fd9ab3a2c856c498b4cc878e09e75f
parent 5f8128535c83d8a45d862cfe1fc1c484ea183c45
Author: Dave Townsend <dtownsend@oxymoronical.com>
Date: Fri, 9 Jan 2026 13:46:50 +0000
Bug 2004469: Avoid using the remoting service when opening external links in the currently running profile. r=profiles-reviewers,jhirsch
Differential Revision: https://phabricator.services.mozilla.com/D277601
Diffstat:
2 files changed, 70 insertions(+), 16 deletions(-)
diff --git a/browser/components/profiles/SelectableProfileService.sys.mjs b/browser/components/profiles/SelectableProfileService.sys.mjs
@@ -1669,10 +1669,58 @@ export class CommandLineHandler {
return null;
}
+ /**
+ * Attempts to parse the arguments expected when opening URLs from other
+ * applications on macOS.
+ *
+ * @param {Array<string>} args The command line arguments.
+ * @returns {boolean} True if the arguments matched the expected form.
+ */
+ openUrls(args) {
+ // Arguments are expected to be in pairs of "-url" "<url>".
+ if (args.length % 2 != 0) {
+ return false;
+ }
+
+ for (let i = 0; i < args.length; i += 2) {
+ if (args[i] != "-url") {
+ return false;
+ }
+ }
+
+ // Now the arguments are verified to only be "-url" arguments we can pass
+ // them directly to the only handler for those arguments.
+ let workingDir = Services.dirsvc.get("CurWorkD", Ci.nsIFile);
+ let cmdLine = Cu.createCommandLine(
+ args,
+ workingDir,
+ Ci.nsICommandLine.STATE_REMOTE_EXPLICIT
+ );
+
+ try {
+ let handler = Cc["@mozilla.org/browser/final-clh;1"].createInstance(
+ Ci.nsICommandLineHandler
+ );
+ handler.handle(cmdLine);
+ } catch (e) {
+ console.error(e);
+ return false;
+ }
+
+ return true;
+ }
+
async redirectCommandLine(args) {
let defaultPath = await this.findDefaultProfilePath();
if (defaultPath) {
+ if (
+ defaultPath == SelectableProfileService.currentProfile.path &&
+ this.openUrls(args)
+ ) {
+ return;
+ }
+
// Attempt to use the remoting service to send the arguments to any
// existing instance of this profile (this even works for the current
// instance on macOS which is the only platform we call this for).
diff --git a/browser/components/profiles/tests/unit/test_command_line_handler.js b/browser/components/profiles/tests/unit/test_command_line_handler.js
@@ -9,6 +9,7 @@ const { sinon } = ChromeUtils.importESModule(
const execProcess = sinon.stub();
const sendCommandLine = sinon.stub().throws(Cr.NS_ERROR_NOT_AVAILABLE);
+const commandLineHandler = sinon.stub();
add_setup(async () => {
await initSelectableProfileService();
@@ -19,6 +20,12 @@ add_setup(async () => {
(path, args, raise) => sendCommandLine(path, [...args], raise)
);
sinon.replace(getSelectableProfileService(), "execProcess", execProcess);
+
+ let { nsDefaultCommandLineHandler: browserClh } = ChromeUtils.importESModule(
+ "resource:///modules/BrowserContentHandler.sys.mjs"
+ );
+
+ sinon.replace(browserClh.prototype, "handle", commandLineHandler);
});
function nextCall(stub) {
@@ -89,29 +96,28 @@ add_task(async function test_redirect_args() {
"Should have prevented the default handler"
);
- await nextCall(execProcess);
+ await nextCall(commandLineHandler);
Assert.equal(
- sendCommandLine.callCount,
+ commandLineHandler.callCount,
1,
- "Should have attempted to remote once"
- );
- Assert.deepEqual(
- sendCommandLine.firstCall.args,
- [profilePath, ["-url", "https://www.google.com/"], true],
- "should have used the right arguments"
+ "Should have called the main browser command line handler directly"
);
- sendCommandLine.resetHistory();
-
- Assert.equal(execProcess.callCount, 1, "Should have attempted to exec once");
- Assert.deepEqual(
- execProcess.firstCall.args,
- [["-foreground", "-url", "https://www.google.com/"]],
- "should have used the right arguments"
+ let [generatedCmdLine] = commandLineHandler.firstCall.args;
+ Assert.equal(
+ generatedCmdLine.length,
+ 2,
+ "Should have generated a command line with the correct number of arguments"
+ );
+ Assert.equal(generatedCmdLine.getArgument(0), "-url");
+ Assert.equal(
+ generatedCmdLine.getArgument(1),
+ "https://www.google.com/",
+ "Should have generated a command line with the correct URL"
);
- execProcess.resetHistory();
+ commandLineHandler.resetHistory();
let profileData = readProfilesIni();