From 364259d0158525ee98167fc21e4a968d56ec753a Mon Sep 17 00:00:00 2001
From: Pier Angelo Vendrame <pierov@torproject.org>
Date: Mon, 11 Sep 2023 15:07:29 +0000
Subject: [PATCH] Bug 1849129: Prevent exceptions caused by extensions from
 interrupting the SearchService initialization. r=search-reviewers,Standard8

Differential Revision: https://phabricator.services.mozilla.com/D186456
---
 .../components/search/SearchService.sys.mjs   | 17 ++++--
 .../test_webextensions_startup_duplicate.js   | 59 +++++++++++++++++++
 .../search/tests/xpcshell/xpcshell.ini        |  1 +
 3 files changed, 72 insertions(+), 5 deletions(-)
 create mode 100644 toolkit/components/search/tests/xpcshell/test_webextensions_startup_duplicate.js

diff --git a/toolkit/components/search/SearchService.sys.mjs b/toolkit/components/search/SearchService.sys.mjs
index afd0fff703f8b..a30c9d64804d4 100644
--- a/toolkit/components/search/SearchService.sys.mjs
+++ b/toolkit/components/search/SearchService.sys.mjs
@@ -1576,11 +1576,18 @@ export class SearchService {
       "engines reported by AddonManager startup"
     );
     for (let extension of this.#startupExtensions) {
-      await this.#installExtensionEngine(
-        extension,
-        [lazy.SearchUtils.DEFAULT_TAG],
-        true
-      );
+      try {
+        await this.#installExtensionEngine(
+          extension,
+          [lazy.SearchUtils.DEFAULT_TAG],
+          true
+        );
+      } catch (ex) {
+        lazy.logConsole.error(
+          `#installExtensionEngine failed for ${extension.id}`,
+          ex
+        );
+      }
     }
     this.#startupExtensions.clear();
 
diff --git a/toolkit/components/search/tests/xpcshell/test_webextensions_startup_duplicate.js b/toolkit/components/search/tests/xpcshell/test_webextensions_startup_duplicate.js
new file mode 100644
index 0000000000000..3e42fdee13eab
--- /dev/null
+++ b/toolkit/components/search/tests/xpcshell/test_webextensions_startup_duplicate.js
@@ -0,0 +1,59 @@
+/* Any copyright is dedicated to the Public Domain.
+   http://creativecommons.org/publicdomain/zero/1.0/ */
+
+"use strict";
+
+const lazy = {};
+
+const { promiseShutdownManager, promiseStartupManager } = AddonTestUtils;
+
+ChromeUtils.defineESModuleGetters(lazy, {
+  ExtensionTestUtils:
+    "resource://testing-common/ExtensionXPCShellUtils.sys.mjs",
+});
+
+add_setup(async function () {
+  let server = useHttpServer();
+  server.registerContentType("sjs", "sjs");
+  await SearchTestUtils.useTestEngines("test-extensions");
+  await promiseStartupManager();
+
+  registerCleanupFunction(async () => {
+    await promiseShutdownManager();
+  });
+});
+
+add_task(async function test_install_duplicate_engine_startup() {
+  let name = "Plain";
+  let id = "plain@tests.mozilla.org";
+  consoleAllowList.push(
+    `#installExtensionEngine failed for ${id}`,
+    `An engine called ${name} already exists`
+  );
+  // Do not use SearchTestUtils.installSearchExtension, as we need to manually
+  // start the search service after installing the extension.
+  let extensionInfo = {
+    useAddonManager: "permanent",
+    files: {},
+    manifest: SearchTestUtils.createEngineManifest({
+      name,
+      search_url: "https://example.com/plain",
+    }),
+  };
+
+  let extension = lazy.ExtensionTestUtils.loadExtension(extensionInfo);
+  await extension.startup();
+
+  await Services.search.init();
+
+  await AddonTestUtils.waitForSearchProviderStartup(extension);
+  let engine = await Services.search.getEngineByName(name);
+  let submission = engine.getSubmission("foo");
+  Assert.equal(
+    submission.uri.spec,
+    "https://duckduckgo.com/?q=foo&t=ffsb",
+    "Should have not changed the app provided engine."
+  );
+
+  await extension.unload();
+});
diff --git a/toolkit/components/search/tests/xpcshell/xpcshell.ini b/toolkit/components/search/tests/xpcshell/xpcshell.ini
index 4f0be19aa60ba..c097af40ae7d5 100644
--- a/toolkit/components/search/tests/xpcshell/xpcshell.ini
+++ b/toolkit/components/search/tests/xpcshell/xpcshell.ini
@@ -191,6 +191,7 @@ support-files = data/search_ignorelist.json
 [test_webextensions_migrate_to.js]
 support-files = data/search-migration.json
 [test_webextensions_normandy_upgrade.js]
+[test_webextensions_startup_duplicate.js]
 [test_webextensions_startup_remove.js]
 [test_webextensions_upgrade.js]
 [test_webextensions_valid.js]
-- 
GitLab