summaryrefslogtreecommitdiffstats
path: root/toolkit/components/search
diff options
context:
space:
mode:
Diffstat (limited to 'toolkit/components/search')
-rw-r--r--toolkit/components/search/AppProvidedSearchEngine.sys.mjs4
-rw-r--r--toolkit/components/search/SearchEngine.sys.mjs12
-rw-r--r--toolkit/components/search/SearchService.sys.mjs24
-rw-r--r--toolkit/components/search/SearchSettings.sys.mjs21
-rw-r--r--toolkit/components/search/SearchSuggestions.sys.mjs7
-rw-r--r--toolkit/components/search/docs/SearchConfigurationSchema.rst722
-rw-r--r--toolkit/components/search/docs/SearchConfigurationSchemaArchive.rst586
-rw-r--r--toolkit/components/search/docs/SearchEngines.rst131
-rw-r--r--toolkit/components/search/docs/SearchEnginesArchive.rst197
-rw-r--r--toolkit/components/search/docs/SearchServiceHighlevelOverview.rst37
-rw-r--r--toolkit/components/search/docs/SearchServiceHighlevelOverviewArchive.rst85
-rw-r--r--toolkit/components/search/docs/assets/search-service-diagram-1.png (renamed from toolkit/components/search/docs/assets/search-service-diagram.png)bin134442 -> 134442 bytes
-rw-r--r--toolkit/components/search/docs/assets/search-service-diagram-2.pngbin0 -> 622630 bytes
-rw-r--r--toolkit/components/search/docs/index.rst3
-rw-r--r--toolkit/components/search/tests/xpcshell/searchconfigs/test_ebay.js36
-rw-r--r--toolkit/components/search/tests/xpcshell/searchconfigs/xpcshell.toml7
-rw-r--r--toolkit/components/search/tests/xpcshell/test_appProvided_engine.js90
-rw-r--r--toolkit/components/search/tests/xpcshell/test_missing_engine.js59
-rw-r--r--toolkit/components/search/tests/xpcshell/test_webextensions_startup.js111
-rw-r--r--toolkit/components/search/tests/xpcshell/test_webextensions_startup_duplicate.js6
-rw-r--r--toolkit/components/search/tests/xpcshell/xpcshell.toml3
21 files changed, 1488 insertions, 653 deletions
diff --git a/toolkit/components/search/AppProvidedSearchEngine.sys.mjs b/toolkit/components/search/AppProvidedSearchEngine.sys.mjs
index ed815b96d1..deceab2b46 100644
--- a/toolkit/components/search/AppProvidedSearchEngine.sys.mjs
+++ b/toolkit/components/search/AppProvidedSearchEngine.sys.mjs
@@ -493,6 +493,10 @@ export class AppProvidedSearchEngine extends SearchEngine {
this._telemetryId += `-${engineConfig.telemetrySuffix}`;
}
+ if (engineConfig.clickUrl) {
+ this.clickUrl = engineConfig.clickUrl;
+ }
+
this._name = engineConfig.name.trim();
this._definedAliases =
engineConfig.aliases?.map(alias => `@${alias}`) ?? [];
diff --git a/toolkit/components/search/SearchEngine.sys.mjs b/toolkit/components/search/SearchEngine.sys.mjs
index 832ffbe2d0..6ce872556e 100644
--- a/toolkit/components/search/SearchEngine.sys.mjs
+++ b/toolkit/components/search/SearchEngine.sys.mjs
@@ -10,6 +10,7 @@ const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
NimbusFeatures: "resource://nimbus/ExperimentAPI.sys.mjs",
+ SearchSettings: "resource://gre/modules/SearchSettings.sys.mjs",
SearchUtils: "resource://gre/modules/SearchUtils.sys.mjs",
OpenSearchEngine: "resource://gre/modules/OpenSearchEngine.sys.mjs",
});
@@ -1228,12 +1229,11 @@ export class SearchEngine {
return;
}
- let engineSettings;
- if (settings.version <= 6) {
- engineSettings = settings.engines?.find(e => e._name == this.name);
- } else {
- engineSettings = settings.engines?.find(e => e.id == this.id);
- }
+ let engineSettings = lazy.SearchSettings.findSettingsForEngine(
+ settings,
+ this.id,
+ this.name
+ );
if (engineSettings?._metaData) {
this._metaData = structuredClone(engineSettings._metaData);
}
diff --git a/toolkit/components/search/SearchService.sys.mjs b/toolkit/components/search/SearchService.sys.mjs
index a645cc05e8..85d673697c 100644
--- a/toolkit/components/search/SearchService.sys.mjs
+++ b/toolkit/components/search/SearchService.sys.mjs
@@ -1801,9 +1801,9 @@ export class SearchService {
this.#addEngineToStore(engine);
} catch (ex) {
console.error(
- `Could not load engine ${
- "webExtension" in config ? config.webExtension.id : "unknown"
- }: ${ex}`
+ "Could not load engine",
+ "webExtension" in config ? config.webExtension.id : "unknown",
+ ex
);
}
}
@@ -1839,7 +1839,8 @@ export class SearchService {
});
} catch (ex) {
lazy.logConsole.error(
- `#createAndAddAddonEngine failed for ${extension.id}`,
+ "#createAndAddAddonEngine failed for",
+ extension.id,
ex
);
}
@@ -2499,6 +2500,19 @@ export class SearchService {
} else if (loadPath?.startsWith("[user]")) {
engine = new lazy.UserSearchEngine({ json: engineJSON });
} else if (engineJSON.extensionID ?? engineJSON._extensionID) {
+ let existingEngine = this.#getEngineByName(engineJSON._name);
+ let extensionId = engineJSON.extensionID ?? engineJSON._extensionID;
+
+ if (existingEngine && existingEngine._extensionID == extensionId) {
+ // We assume that this WebExtension was already loaded as part of
+ // #loadStartupEngines, and therefore do not try to add it again.
+ lazy.logConsole.log(
+ "Ignoring already added WebExtension",
+ extensionId
+ );
+ continue;
+ }
+
engine = new lazy.AddonSearchEngine({
isAppProvided: false,
json: engineJSON,
@@ -2587,7 +2601,7 @@ export class SearchService {
async _fetchEngineSelectorEngines() {
let searchEngineSelectorProperties = {
locale: Services.locale.appLocaleAsBCP47,
- region: lazy.Region.home || "default",
+ region: lazy.Region.home || "unknown",
channel: lazy.SearchUtils.MODIFIED_APP_CHANNEL,
experiment:
lazy.NimbusFeatures.searchConfiguration.getVariable("experiment") ?? "",
diff --git a/toolkit/components/search/SearchSettings.sys.mjs b/toolkit/components/search/SearchSettings.sys.mjs
index e355316595..b4db403bb0 100644
--- a/toolkit/components/search/SearchSettings.sys.mjs
+++ b/toolkit/components/search/SearchSettings.sys.mjs
@@ -616,6 +616,27 @@ export class SearchSettings {
}
/**
+ * Finds the settings for the engine, based on the version of the settings
+ * passed in. Older versions of settings used the engine name as the key,
+ * whereas newer versions now use the engine id.
+ *
+ * @param {object} settings
+ * The saved settings object.
+ * @param {string} engineId
+ * The id of the engine.
+ * @param {string} engineName
+ * The name of the engine.
+ * @returns {object|undefined}
+ * The engine settings if found, undefined otherwise.
+ */
+ static findSettingsForEngine(settings, engineId, engineName) {
+ if (settings.version <= 6) {
+ return settings.engines?.find(e => e._name == engineName);
+ }
+ return settings.engines?.find(e => e.id == engineId);
+ }
+
+ /**
* Returns the engine associated with the name without SearchService
* initialization checks.
*
diff --git a/toolkit/components/search/SearchSuggestions.sys.mjs b/toolkit/components/search/SearchSuggestions.sys.mjs
index 4a43975576..83bf665bcf 100644
--- a/toolkit/components/search/SearchSuggestions.sys.mjs
+++ b/toolkit/components/search/SearchSuggestions.sys.mjs
@@ -6,7 +6,6 @@ const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
FormHistoryAutoCompleteResult:
"resource://gre/modules/FormHistoryAutoComplete.sys.mjs",
- FormHistoryClient: "resource://gre/modules/FormHistoryAutoComplete.sys.mjs",
SearchSuggestionController:
"resource://gre/modules/SearchSuggestionController.sys.mjs",
@@ -156,10 +155,6 @@ class SuggestAutoComplete {
// Bug 1822297: This re-uses the wrappers from Satchel, to avoid re-writing
// our own nsIAutoCompleteSimpleResult implementation for now. However,
// we should do that at some stage to remove the dependency on satchel.
- let client = new lazy.FormHistoryClient({
- formField: null,
- inputName: this.#suggestionController.formHistoryParam,
- });
let formHistoryEntries = (results?.formHistoryResults ?? []).map(
historyEntry => ({
// We supply the comments field so that autocomplete does not kick
@@ -170,7 +165,7 @@ class SuggestAutoComplete {
})
);
let autoCompleteResult = new lazy.FormHistoryAutoCompleteResult(
- client,
+ null,
formHistoryEntries,
this.#suggestionController.formHistoryParam,
searchString
diff --git a/toolkit/components/search/docs/SearchConfigurationSchema.rst b/toolkit/components/search/docs/SearchConfigurationSchema.rst
index b57f69fe13..ceeaa5cb57 100644
--- a/toolkit/components/search/docs/SearchConfigurationSchema.rst
+++ b/toolkit/components/search/docs/SearchConfigurationSchema.rst
@@ -2,8 +2,9 @@
Search Configuration Schema
===========================
-This document outlines the details of the schema and how the various sub-parts
-interact. For the full fields and descriptions, please see the `schema itself`_.
+This document outlines the details of the `search-config-v2`_ schema and how
+the various sub-parts interact. For the full fields and descriptions, please see
+the `schema itself`_.
.. note::
In the examples, only relevant properties are displayed.
@@ -11,452 +12,255 @@ interact. For the full fields and descriptions, please see the `schema itself`_.
Overview
========
-The configuration is a JSON blob which is object with a `data` property which
-is an array of engines:
+The configuration is a JSON blob, an object with a ``data`` property and value
+as an array containing ``engine``, ``defaultEngines``, and ``engineOrders``
+record types:
.. code-block:: js
{
data: [
{
+ // defaultEngines details
+ },
+ {
// engine 1 details
},
{
// engine 2 details
- }
- ]
- }
-
-Engine Objects
-==============
-
-An engine's details are located in the properties of the object associated with it.
-An engine that is deployed globally could be listed simply as:
-
-.. code-block:: js
-
- {
- "default": "no",
- "telemetryId": "engine1-telem",
- "webExtension": {
- "id": "web@ext"
- },
- "appliesTo": [{
- "included": {
- "everywhere": true
- }
- }]
- }
-
-The ``appliesTo`` section is an array of objects. At least one object is required
-to specify which regions/locales the engine is included within. If an
-``appliesTo`` object lists additional attributes then these will override any
-attributes at the top-level.
-
-For example, a more complex engine definition may be available only to users
-located specific regions or with certain locales. For example:
-
-.. code-block:: js
-
- {
- "webExtension": {
- "id": "web@ext"
- },
- "appliesTo": [{
- "included": {
- "region": "us"
},
- "webExtension": {
- "id": "web-us@ext"
- }
- }, {
- "included": {
- "region": "gb"
- },
- "webExtension": {
- "id": "web-gb@ext"
- }
- }]
- }
-
-In this case users identified as being in the US region would use the WebExtension
-with identifier ``web-us@ext``. GB region users would get
-``web-gb@ext``, and all other users would get ``web@ext``.
-
-To direct search engines to pull ``_locale`` data from a specific locale
-directory, you can use ``webExtension.locales``.
-
-For example, in this code block:
-
-.. code-block:: js
-
- {
- "webExtension": {
- "id": "web@ext"
- },
- "appliesTo": [
{
- "included": {
- "locales": "en-US"
- },
- "webExtension": {
- "locales": [
- "us"
- ]
- }
- }, {
- "included": {
- "locales": "en-GB"
- },
- "webExtension": {
- "locales": [
- "uk"
- ]
- }
- }
- ]
- }
-
-There should exist a ``us`` and ``uk`` folder in the ``locales`` directory
-of the extension, ``web``.
-
-If a locale is not provided, ``webExtension.locales`` is set to
-``SearchUtils.DEFAULT_TAG``.
-
-`Search Extensions directory <https://searchfox.org/mozilla-central/source/browser/components/search/extensions>`__
-
-`Example of a locales directory <https://searchfox.org/mozilla-central/source/browser/components/search/extensions/wikipedia/_locales>`__
-
-
-Special Attributes
-==================
-
-$USER_LOCALE
-------------
-
-If a ``webExtension.locales`` property contains an element with the value
-``"$USER_LOCALE"`` then the special value will be replaced in the
-configuration object with the users locale. For example:
-
-.. code-block:: js
-
- {
- "webExtension": {
- "id": "web@ext"
- },
- "appliesTo": [{
- "included": {
- "locales": {
- "matches": [
- "en-US",
- "en-GB"
- ]
- }
+ // engineOrders details
},
- "webExtension": {
- "locales": ["$USER_LOCALE"]
- }
- }]
+ ]
}
-Will report either ``[en-US]`` or ``[en-GB]`` as the ``webExtension.locales``
-property depending on the user's locale.
-
-Since the special string is replaced, custom folder names can be searched for
-by adding the keyword in between a consistent prefix/suffix.
-
-For example, if ``webExtension.locales`` was ``["example-$USER_LOCALE"]``,
-the locale generator will generate locale names in the form of ``example-en-US``
-and ``example-en-GB``.
+Environment
+===========
+An ``environment`` property is contained within each of the record types and is
+used to determine where some, or all, of that record is applied to according to
+the user's detected environment. There are many different properties in ``environment``.
+These may be used individually or together to build up a match. Here is the list
+of those properties:
+
+``allRegionsAndLocales``
+ - ``"environment": { "allRegionsAndLocales": true }``
+ - Indicates that this section applies to all regions and locales. May be
+ modified by excludedRegions/excludedLocales.
+
+``applications``
+ - ``"environment": { "applications": ["firefox"] }``
+ - This property specifies the applications the record would be applied to.
+ - Some applications we support are ``firefox``, ``firefox-android``, ``firefox-ios``,
+ ``focus-android``, and ``focus-ios``.
+
+``channels``
+ - ``"environment": { "channels": ["default"] }``
+ - One or more channels may be specified in an array to restrict a configuration
+ to just those channels. The following is a list of the channels:
-Note: Prior to Firefox 100.0, $USER_LOCALE used an exact match.
-In Firefox 100.0 the replacement was updated to use a standard string replacement.
+ - default: Self-builds of Firefox, or possibly some self-distributed versions.
+ - nightly: Firefox Nightly builds.
+ - aurora: Firefox Developer Edition.
+ - beta: Firefox Beta.
+ - release: The main Firefox release channel.
+ - esr: The ESR Channel. This will also match versions of Firefox where the
+ displayed version number includes ``esr``. We do this to include Linux
+ distributions and other manual builds of ESR.
-From Firefox 98.0.1 and 97.7.1esr, ``"$USER_LOCALE"`` may also be used in the
-``telemetryId`` field.
+``distributions``
+ - ``"environment": { "distributions": ["distribution-name"] }``
+ - An array of distribution identifiers that the record object applies to.
+ - The identifiers match those supplied by the ``distribution.id`` preference.
+
+``excludedDistributions``
+ - ``"environment": { "distributions": ["distribution-excluded"] }``
+ - An array of distribution identifiers that the record object does not apply to.
+
+``excludedLocales``
+ - ``"environment": { "excludedLocales": ["de"] }``
+ - An array of locales that this section should be excluded from.
+
+``excludedRegions``
+ - ``"environment": { "excludedRegions": ["ca"] }``
+ - An array of regions that this section should be excluded from.
+
+``experiment``
+ - ``"environment": { "experiment": "experimental" }``
+ - Experiments can be run by giving a value to the ``experiment`` property.
+ - The experiment value should also be supplied to the ``experiment`` property
+ of the ``searchConfiguration`` feature on Nimbus.
+
+``locales``
+ - ``"environment": { "locales": ["en-US"] }``
+ - An array of locales that this section applies to.
+
+``regions``
+ - ``"environment": { "regions": ["ca"] }``
+ - An array of regions that this section applies to.
+ - ``"unknown"`` may be used to apply to situations where we have not been able
+ to detect the user's region. However, this is not currently expected to be used.
+
+``maxVersion`` and ``minVersion``
+ - Minimum and Maximum versions may be specified to restrict a configuration to
+ specific ranges. These may be open-ended. Version comparison is performed
+ using `the version comparator`_.
+ - Note: comparison against ``maxVersion`` is a less-than comparison. The
+ ``maxVersion`` won't be matched directly.
+ - ``"environment": { "minVersion": "72.0a1" }`` Indicates the record object
+ will be included for any version after 72.0a1.
+ - ``"environment": { "minVersion": "68.0a1", "maxVersion": "72.0a1" }``
+ Indicates the record object would be included only between 68.0a1 and 71.x
+ version.
-$USER_REGION
-------------
+Engine Objects
+==============
-This can be used in the same situations as ``"$USER_LOCALE"``, instead
-replacing ``webExtension.locale`` with a string that uses the users region.
+Each engine object represents a search engine that may be presented to a user.
+Each engine object is treated as a separate engine within the application, with
+independent settings.
.. code-block:: js
{
- "webExtension": {
- "id": "web@ext"
- },
- "appliesTo": [{
- "included": {
- "everywhere": true
+ "base": {
+ "classification": "general"
+ "name": "engine1 name",
+ "partnerCode": "bar",
+ "urls": {
+ "search": {
+ "base": "https://www.example.com",
+ "params": [
+ {
+ "name": "code",
+ "value": "{partnerCode}"
+ }
+ ],
+ "searchTermParamName": "q"
+ },
},
- "webExtension": {
- "locales": ["foo-$USER_REGION"]
- }
- }]
- }
-
-In this example, if the user's region is ``fr``, the ``webExtension.locale``
-will be ``foo-fr``, and the code will look for the ``messages.json`` in
-the ``foo-fr`` folder of the ``_locales`` folder for this extension.
-
-Note: ``"$USER_REGION"`` was added in Firefox 98.0.1 and 97.7.1esr and used an exact match.
-In Firefox 100.0 the replacement was updated to use a standard string replacement.
-
-"default"
----------
-
-You can specify ``"default"`` as a region in the configuration if
-the engine is to be included when we do not know the user's region.
-
-"override"
-----------
-
-The ``"override"`` field can be set to true if you want a section to
-only override otherwise included engines. ``"override"`` will only work for
-sections which apply to distributions or experiments. The experiment case was
-added in Firefox 81.
-
-Starting with Firefox 96, ``"override"`` sections may include ``included`` and
-``excluded`` information which will be applied accordingly. If they are not
-supplied, then the override section will be applied to everywhere.
-
-Example:
-
-.. code-block:: js
-
- {
- "webExtension": {
- "id": "web@ext"
},
- "appliesTo": [{
- // Complicated and lengthy inclusion rules
- }, {
- "override": true,
- "application": { "distributions": ["mydistrocode"]},
- "params": {
- "searchUrlGetParams": [
- { "name": "custom", "value": "foobar" }
- ]
+ "identifier": "engine1",
+ "recordType": "engine",
+ "variants": [
+ {
+ "environment": { "allRegionsAndLocales": true }
}
- }]
+ ]
}
-Application Scoping
-===================
-
-An engine configuration may be scoped to a particular application.
+The required **top-level** properties are:
-Name
-----
+- ``base`` Defines the base details for the engine. The required base properties
+ are ``classification``, ``name``, and ``urls``.
-One or more application names may be specified. Currently the only application
-type supported is ``firefox``. If an application name is specified, then it
-must be matched for the section to apply. If there are no application names
-specified, then the section will match any consumer of the configuration.
+ - The ``urls`` may be different types of urls. These various types include
+ ``search``, ``suggestions``, and ``trending`` urls. The url property contains
+ the base url and any query string params to build the complete url. If
+ ``engine1`` is used to search ``kitten``, the search url will be constructed
+ as ``https://www.example.com/?code=bar&q=kitten``. Notice the ``partnerCode``
+ from the base is inserted into parameters ``{partnerCode}`` value of the search url.
+- ``identifier`` Identifies the search engine and is used internally to set the telemetry id.
+- ``recordType`` The type of record the object is. Always ``engine`` for engine
+ objects.
+- ``variants`` Specifies the environment the engine is included in, which details
+ the region, locale, and other environment properties.
-In the following example, ``web@ext`` would be included on any consumer
-of the configuration, but ``web1@ext`` would only be included on Firefox desktop.
+Engine Variants
+===============
+A engine may be available only to users located in specific regions or with
+certain locales. For example, when the ``environment`` section of variants specify
+locales and regions:
.. code-block:: js
- {
- "webExtension": {
- "id": "web@ext"
- },
- "appliesTo": [{
- "included": {
- "everywhere": true
- "application": {
- "name": []
- }
- }
- ]}
- },
- {
- "webExtension": {
- "id": "web1@ext"
- },
- "appliesTo": [{
- "included": {
- "everywhere": true
- "application": {
- "name": ["firefox"]
- }
- }
- ]}
- }
+ "variants": [
+ {
+ "environment": { "locales": ["en-US"], "regions": ["US"] }
+ }
+ ]
-Channel
--------
+In this case users identified as being in the ``en-US`` locale and ``US`` region
+would be able to have the engine available.
-One or more channels may be specified in an array to restrict a configuration
-to just those channels. The current known channels are:
+**Multiple Variants**
- - default: Self-builds of Firefox, or possibly some self-distributed versions.
- - nightly: Firefox Nightly builds.
- - aurora: Firefox Developer Edition
- - beta: Firefox Beta
- - release: The main Firefox release channel.
- - esr: The ESR Channel. This will also match versions of Firefox where the
- displayed version number includes ``esr``. We do this to include Linux
- distributions and other manual builds of ESR.
-
-In the following example, ``web@ext`` would be set as default on the default
-channel only, whereas ``web1@ext`` would be set as default on release and esr
-channels.
+When there are more than one variant the last matching variant will be applied.
.. code-block:: js
+ "variants": [
{
- "webExtension": {
- "id": "web@ext"
- },
- "appliesTo": [{
- "included": {
- "everywhere": true
- "default": "yes",
- "application": {
- "channel": ["default"]
- }
- }
- ]}
+ "environment": { "locales": ["en-US"] }
+ "partnerCode": "bar"
},
{
- "webExtension": {
- "id": "web1@ext"
- },
- "appliesTo": [{
- "included": {
- "everywhere": true
- "default": "yes",
- "application": {
- "channel": ["release", "esr"]
- }
- }
- ]}
- }
-
-Distributions
--------------
-
-Distributions may be specified to be included or excluded in an ``appliesTo``
-section. The ``distributions`` field in the ``application`` section is an array
-of distribution identifiers. The identifiers match those supplied by the
-``distribution.id`` preference.
-
-In the following, ``web@ext`` would be included in only the ``cake``
-distribution. ``web1@ext`` would be excluded from the ``apples`` distribution
-but included in the main desktop application, and all other distributions.
-
-.. code-block:: js
-
- {
- "webExtension": {
- "id": "web@ext"
- },
- "appliesTo": [{
- "included": {
- "everywhere": true
- "application": {
- "distributions": ["cake"]
- }
- }
- ]}
+ "environment": { "locales": ["en-US"], "regions": ["US"]}
+ "partnerCode": "foo"
},
- {
- "webExtension": {
- "id": "web1@ext"
- },
- "appliesTo": [{
- "included": {
- "everywhere": true
- "application": {
- "excludedDistributions": ["apples"]
- }
- }
- ]}
- }
+ ]
-Version
--------
+In this case users identified in ``en-US`` locale and ``US`` region matched
+both the variants. Users in ``en-US`` locale and ``US`` region matched the
+first variant because it has ``en-US`` locales and when regions is not specified,
+it means all regions are included. Then it matched the second variant because it matched
+``en-US`` locale and ``US`` region. The result will be that for this user the
+partner code will have value ``foo``.
-Minimum and Maximum versions may be specified to restrict a configuration to
-specific ranges. These may be open-ended. Version comparison is performed
-using `the version comparator`_.
-
-Note: comparison against ``maxVersion`` is a less-than comparison. The
-``maxVersion`` won't be matched directly.
-
-In the following example, ``web@ext`` would be included for any version after
-72.0a1, whereas ``web1@ext`` would be included only between 68.0a1 and 71.x
-version.
+Engine Subvariants
+==================
+Nested within ``variants`` may be an array of ``subVariants``. Subvariants
+contain the same properties as variants except the ``subVariants`` property. The
+purpose of subvariants is for the combination of environment properties from the
+last matched subvariant and the top level variant.
.. code-block:: js
- {
- "webExtension": {
- "id": "web@ext"
- },
- "appliesTo": [{
- "included": {
- "everywhere": true
- "application": {
- "minVersion": "72.0a1"
- }
- }
- ]}
- },
- {
- "webExtension": {
- "id": "web1@ext"
- },
- "appliesTo": [{
- "included": {
- "everywhere": true
- "default": "yes",
- "application": {
- "minVersion": "68.0a1"
- "maxVersion": "72.0a1"
- }
- }
- ]}
- }
+ "variants": [
+ {
+ "environment": { "regions": ["US", "CA", "GB"] }
+ "subVariants": [
+ {
+ "environment": { "channels": [ "esr"] },
+ "partnerCode": "bar",
+ },
+ ]
+ }
+ ]
-Experiments
-===========
+In this case users identified as being in ``US`` region and ``esr`` channel
+would match the subvariant and would be able to have the engine available with
+partner code ``bar`` applied.
-We can run experiments by giving sections within ``appliesTo`` a
-``experiment`` value, the Search Service can then optionally pass in a
-matching ``experiment`` value to match those sections.
+**Multiple Subvariants**
-Sections which have a ``experiment`` will not be used unless a matching
-``experiment`` has been passed in, for example:
+When there are more than one subvariant the last matching subvariant will be
+applied.
.. code-block:: js
+ "variants": [
{
- "webExtension": {
- "id": "web@ext"
- },
- "appliesTo": [{
- "included": {
- "everywhere": true
- },
- "experiment": "nov-16",
- "webExtension": {
- "id": "web-experimental@ext"
- }
- }, {
- "included": {
- "everywhere": true
+ "environment": { "regions": ["US", "CA", "GB"] }
+ "subVariants": [
+ {
+ "environment": { "channels": [ "esr"] },
+ "partnerCode": "bar",
},
- "webExtension": {
- "id": "web-gb@ext"
+ {
+ "environment": { "channels": [ "esr"], "locales": ["fr"] },
+ "partnerCode": "foo",
}
- }]
+ ]
}
+ ]
+
+In this case users identified in ``US`` region, ``fr`` locale, and ``esr`` channel
+matched both the subvariants. It matched the first subvariant because the first
+environment has ``US`` region from the top-level variant, ``esr`` channel, and
+all locales. Then it matched the second variant because the second environment
+has ``US`` region from top-level variant, ``fr`` locale, and ``esr`` channel.
+The user will receive the last matched subvariant with partner code ``foo``.
Engine Defaults
===============
@@ -472,115 +276,85 @@ pair, then the normal mode engine is used.
If the instance of the application does not support a separate private browsing mode engine,
then it will only use the normal mode engine.
-An engine may or may not be default for particular regions/locales. The ``default``
-property is a tri-state value with states of ``yes``, ``yes-if-no-other`` and
-``no``. Here's an example of how they apply:
+An engine may or may not be default for particular regions/locales. The
+``defaultEngines`` record is structured to provide ``globalDefault`` and
+``globalDefaultPrivate`` properties, these properties define the user's engine
+if there are no ``specificDefaults`` sections that match the user's environment.
+The ``specificDefaults`` sections can define different engines that match with
+specific user environments.
.. code-block:: js
{
- "webExtension": {
- "id": "engine1@ext"
- },
- "appliesTo": [{
- "included": {
- "region": "us"
- },
- "default": "yes"
- }, {
- "excluded": {
- "region": "us"
- },
- "default": "yes-if-no-other"
- }]
- },
- {
- "webExtension": {
- "id": "engine2@ext"
- },
- "appliesTo": [{
- "included": {
- "region": "gb"
- },
- "default": "yes"
- }]
- },
- "webExtension": {
- "id": "engine3@ext"
- },
- "default": "no"
- "appliesTo": [{
- "included": {
- "everywhere": true
- },
- }]
- },
- {
- "webExtension": {
- "id": "engine4@ext"
- },
- "defaultPrivate": "yes",
- "appliesTo": [{
- "included": {
- "region": "fr"
+ "globalDefault": "engine1",
+ "globalDefaultPrivate": "engine1",
+ "recordType": "defaultEngines",
+ "specificDefaults": [
+ {
+ "default": "engine2",
+ "defaultPrivate": "engine3"
+ "environment": {
+ "locales": [
+ "en-CA"
+ ],
+ "regions": [
+ "CA"
+ ]
+ },
}
- }]
+ ]
}
-In this example, for normal mode:
- - engine1@ext is default in the US region, and all other regions except for GB
- - engine2@ext is default in only the GB region
- - engine3@ext and engine4 are never default anywhere
+In normal mode:
+
+ - engine1 is default for all regions except for region CA locale en-CA
+ - engine2 is default in only the CA region and locale en-CA
In private browsing mode:
- - engine1@ext is default in the US region, and all other regions except for GB and FR
- - engine2@ext is default in only the GB region
- - engine3@ext is never default anywhere
- - engine4@ext is default in the FR region.
+ - engine1 is private default for all regions except for region CA locale en-CA
+ - engine3 is private default in only the CA region and locale en-CA
Engine Ordering
===============
-The ``orderHint`` field indicates the suggested ordering of an engine relative to
-other engines when displayed to the user, unless the user has customized their
-ordering.
+The ``engineOrders`` record type indicates the suggested ordering of an engine
+relative to other engines when displayed to the user, unless the user has
+customized their ordering. The ordering is listed in the ``order`` property, an
+ordered array with the first engine being at the lowest index.
-The default ordering of engines is based on a combination of if the engine is
-default, and the ``orderHint`` fields. The ordering is structured as follows:
+If there is no matching order for the user's environment, then this order applies:
-#. Default engine in normal mode
-#. Default engine in private browsing mode (if different from the normal mode engine)
-#. Other engines in order from the highest ``orderHint`` to the lowest.
+#. Default Engine
+#. Default Private Engine (if any)
+#. Other engines in alphabetical order.
Example:
.. code-block:: js
{
- "webExtension": {
- "id": "engine1@ext"
- },
- "orderHint": 2000,
- "default": "no",
- },
- {
- "webExtension": {
- "id": "engine2@ext"
- },
- "orderHint": 1000,
- "default": "yes"
- },
- {
- "webExtension": {
- "id": "engine3@ext"
- },
- "orderHint": 500,
- "default": "no"
+ "orders": [
+ {
+ "environment": {
+ "distributions": [
+ "distro"
+ ]
+ },
+ "order": [
+ "c-engine",
+ "b-engine",
+ "a-engine",
+ ]
+ }
+ ]
+ "recordType": "engineOrders",
}
-This would result in the order: ``engine2@ext, engine1@ext, engine3@ext``.
+This would result in the order: ``c-engine``, ``b-engine``, ``a-engine`` for the
+distribution ``distro``.
.. _schema itself: https://searchfox.org/mozilla-central/source/toolkit/components/search/schema/
-.. _the version comparator: https://developer.mozilla.org/en-US/docs/Mozilla/Toolkit_version_format
+.. _the version comparator: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/version/format
+.. _search-config-v2: https://searchfox.org/mozilla-central/source/services/settings/dumps/main/search-config-v2.json
diff --git a/toolkit/components/search/docs/SearchConfigurationSchemaArchive.rst b/toolkit/components/search/docs/SearchConfigurationSchemaArchive.rst
new file mode 100644
index 0000000000..a22054d6c0
--- /dev/null
+++ b/toolkit/components/search/docs/SearchConfigurationSchemaArchive.rst
@@ -0,0 +1,586 @@
+======================================
+Search Configuration Schema (Archived)
+======================================
+
+This document outlines the details of the schema and how the various sub-parts
+interact. For the full fields and descriptions, please see the `schema itself`_.
+
+.. note::
+ In the examples, only relevant properties are displayed.
+
+Overview
+========
+
+The configuration is a JSON blob which is object with a `data` property which
+is an array of engines:
+
+.. code-block:: js
+
+ {
+ data: [
+ {
+ // engine 1 details
+ },
+ {
+ // engine 2 details
+ }
+ ]
+ }
+
+Engine Objects
+==============
+
+An engine's details are located in the properties of the object associated with it.
+An engine that is deployed globally could be listed simply as:
+
+.. code-block:: js
+
+ {
+ "default": "no",
+ "telemetryId": "engine1-telem",
+ "webExtension": {
+ "id": "web@ext"
+ },
+ "appliesTo": [{
+ "included": {
+ "everywhere": true
+ }
+ }]
+ }
+
+The ``appliesTo`` section is an array of objects. At least one object is required
+to specify which regions/locales the engine is included within. If an
+``appliesTo`` object lists additional attributes then these will override any
+attributes at the top-level.
+
+For example, a more complex engine definition may be available only to users
+located specific regions or with certain locales. For example:
+
+.. code-block:: js
+
+ {
+ "webExtension": {
+ "id": "web@ext"
+ },
+ "appliesTo": [{
+ "included": {
+ "region": "us"
+ },
+ "webExtension": {
+ "id": "web-us@ext"
+ }
+ }, {
+ "included": {
+ "region": "gb"
+ },
+ "webExtension": {
+ "id": "web-gb@ext"
+ }
+ }]
+ }
+
+In this case users identified as being in the US region would use the WebExtension
+with identifier ``web-us@ext``. GB region users would get
+``web-gb@ext``, and all other users would get ``web@ext``.
+
+To direct search engines to pull ``_locale`` data from a specific locale
+directory, you can use ``webExtension.locales``.
+
+For example, in this code block:
+
+.. code-block:: js
+
+ {
+ "webExtension": {
+ "id": "web@ext"
+ },
+ "appliesTo": [
+ {
+ "included": {
+ "locales": "en-US"
+ },
+ "webExtension": {
+ "locales": [
+ "us"
+ ]
+ }
+ }, {
+ "included": {
+ "locales": "en-GB"
+ },
+ "webExtension": {
+ "locales": [
+ "uk"
+ ]
+ }
+ }
+ ]
+ }
+
+There should exist a ``us`` and ``uk`` folder in the ``locales`` directory
+of the extension, ``web``.
+
+If a locale is not provided, ``webExtension.locales`` is set to
+``SearchUtils.DEFAULT_TAG``.
+
+`Search Extensions directory <https://searchfox.org/mozilla-central/source/browser/components/search/extensions>`__
+
+`Example of a locales directory <https://searchfox.org/mozilla-central/source/browser/components/search/extensions/wikipedia/_locales>`__
+
+
+Special Attributes
+==================
+
+$USER_LOCALE
+------------
+
+If a ``webExtension.locales`` property contains an element with the value
+``"$USER_LOCALE"`` then the special value will be replaced in the
+configuration object with the users locale. For example:
+
+.. code-block:: js
+
+ {
+ "webExtension": {
+ "id": "web@ext"
+ },
+ "appliesTo": [{
+ "included": {
+ "locales": {
+ "matches": [
+ "en-US",
+ "en-GB"
+ ]
+ }
+ },
+ "webExtension": {
+ "locales": ["$USER_LOCALE"]
+ }
+ }]
+ }
+
+Will report either ``[en-US]`` or ``[en-GB]`` as the ``webExtension.locales``
+property depending on the user's locale.
+
+Since the special string is replaced, custom folder names can be searched for
+by adding the keyword in between a consistent prefix/suffix.
+
+For example, if ``webExtension.locales`` was ``["example-$USER_LOCALE"]``,
+the locale generator will generate locale names in the form of ``example-en-US``
+and ``example-en-GB``.
+
+Note: Prior to Firefox 100.0, $USER_LOCALE used an exact match.
+In Firefox 100.0 the replacement was updated to use a standard string replacement.
+
+From Firefox 98.0.1 and 97.7.1esr, ``"$USER_LOCALE"`` may also be used in the
+``telemetryId`` field.
+
+$USER_REGION
+------------
+
+This can be used in the same situations as ``"$USER_LOCALE"``, instead
+replacing ``webExtension.locale`` with a string that uses the users region.
+
+.. code-block:: js
+
+ {
+ "webExtension": {
+ "id": "web@ext"
+ },
+ "appliesTo": [{
+ "included": {
+ "everywhere": true
+ },
+ "webExtension": {
+ "locales": ["foo-$USER_REGION"]
+ }
+ }]
+ }
+
+In this example, if the user's region is ``fr``, the ``webExtension.locale``
+will be ``foo-fr``, and the code will look for the ``messages.json`` in
+the ``foo-fr`` folder of the ``_locales`` folder for this extension.
+
+Note: ``"$USER_REGION"`` was added in Firefox 98.0.1 and 97.7.1esr and used an exact match.
+In Firefox 100.0 the replacement was updated to use a standard string replacement.
+
+"default"
+---------
+
+You can specify ``"default"`` as a region in the configuration if
+the engine is to be included when we do not know the user's region.
+
+"override"
+----------
+
+The ``"override"`` field can be set to true if you want a section to
+only override otherwise included engines. ``"override"`` will only work for
+sections which apply to distributions or experiments. The experiment case was
+added in Firefox 81.
+
+Starting with Firefox 96, ``"override"`` sections may include ``included`` and
+``excluded`` information which will be applied accordingly. If they are not
+supplied, then the override section will be applied to everywhere.
+
+Example:
+
+.. code-block:: js
+
+ {
+ "webExtension": {
+ "id": "web@ext"
+ },
+ "appliesTo": [{
+ // Complicated and lengthy inclusion rules
+ }, {
+ "override": true,
+ "application": { "distributions": ["mydistrocode"]},
+ "params": {
+ "searchUrlGetParams": [
+ { "name": "custom", "value": "foobar" }
+ ]
+ }
+ }]
+ }
+
+Application Scoping
+===================
+
+An engine configuration may be scoped to a particular application.
+
+Name
+----
+
+One or more application names may be specified. Currently the only application
+type supported is ``firefox``. If an application name is specified, then it
+must be matched for the section to apply. If there are no application names
+specified, then the section will match any consumer of the configuration.
+
+In the following example, ``web@ext`` would be included on any consumer
+of the configuration, but ``web1@ext`` would only be included on Firefox desktop.
+
+.. code-block:: js
+
+ {
+ "webExtension": {
+ "id": "web@ext"
+ },
+ "appliesTo": [{
+ "included": {
+ "everywhere": true
+ "application": {
+ "name": []
+ }
+ }
+ ]}
+ },
+ {
+ "webExtension": {
+ "id": "web1@ext"
+ },
+ "appliesTo": [{
+ "included": {
+ "everywhere": true
+ "application": {
+ "name": ["firefox"]
+ }
+ }
+ ]}
+ }
+
+Channel
+-------
+
+One or more channels may be specified in an array to restrict a configuration
+to just those channels. The current known channels are:
+
+ - default: Self-builds of Firefox, or possibly some self-distributed versions.
+ - nightly: Firefox Nightly builds.
+ - aurora: Firefox Developer Edition
+ - beta: Firefox Beta
+ - release: The main Firefox release channel.
+ - esr: The ESR Channel. This will also match versions of Firefox where the
+ displayed version number includes ``esr``. We do this to include Linux
+ distributions and other manual builds of ESR.
+
+In the following example, ``web@ext`` would be set as default on the default
+channel only, whereas ``web1@ext`` would be set as default on release and esr
+channels.
+
+.. code-block:: js
+
+ {
+ "webExtension": {
+ "id": "web@ext"
+ },
+ "appliesTo": [{
+ "included": {
+ "everywhere": true
+ "default": "yes",
+ "application": {
+ "channel": ["default"]
+ }
+ }
+ ]}
+ },
+ {
+ "webExtension": {
+ "id": "web1@ext"
+ },
+ "appliesTo": [{
+ "included": {
+ "everywhere": true
+ "default": "yes",
+ "application": {
+ "channel": ["release", "esr"]
+ }
+ }
+ ]}
+ }
+
+Distributions
+-------------
+
+Distributions may be specified to be included or excluded in an ``appliesTo``
+section. The ``distributions`` field in the ``application`` section is an array
+of distribution identifiers. The identifiers match those supplied by the
+``distribution.id`` preference.
+
+In the following, ``web@ext`` would be included in only the ``cake``
+distribution. ``web1@ext`` would be excluded from the ``apples`` distribution
+but included in the main desktop application, and all other distributions.
+
+.. code-block:: js
+
+ {
+ "webExtension": {
+ "id": "web@ext"
+ },
+ "appliesTo": [{
+ "included": {
+ "everywhere": true
+ "application": {
+ "distributions": ["cake"]
+ }
+ }
+ ]}
+ },
+ {
+ "webExtension": {
+ "id": "web1@ext"
+ },
+ "appliesTo": [{
+ "included": {
+ "everywhere": true
+ "application": {
+ "excludedDistributions": ["apples"]
+ }
+ }
+ ]}
+ }
+
+Version
+-------
+
+Minimum and Maximum versions may be specified to restrict a configuration to
+specific ranges. These may be open-ended. Version comparison is performed
+using `the version comparator`_.
+
+Note: comparison against ``maxVersion`` is a less-than comparison. The
+``maxVersion`` won't be matched directly.
+
+In the following example, ``web@ext`` would be included for any version after
+72.0a1, whereas ``web1@ext`` would be included only between 68.0a1 and 71.x
+version.
+
+.. code-block:: js
+
+ {
+ "webExtension": {
+ "id": "web@ext"
+ },
+ "appliesTo": [{
+ "included": {
+ "everywhere": true
+ "application": {
+ "minVersion": "72.0a1"
+ }
+ }
+ ]}
+ },
+ {
+ "webExtension": {
+ "id": "web1@ext"
+ },
+ "appliesTo": [{
+ "included": {
+ "everywhere": true
+ "default": "yes",
+ "application": {
+ "minVersion": "68.0a1"
+ "maxVersion": "72.0a1"
+ }
+ }
+ ]}
+ }
+
+Experiments
+===========
+
+We can run experiments by giving sections within ``appliesTo`` a
+``experiment`` value, the Search Service can then optionally pass in a
+matching ``experiment`` value to match those sections.
+
+Sections which have a ``experiment`` will not be used unless a matching
+``experiment`` has been passed in, for example:
+
+.. code-block:: js
+
+ {
+ "webExtension": {
+ "id": "web@ext"
+ },
+ "appliesTo": [{
+ "included": {
+ "everywhere": true
+ },
+ "experiment": "nov-16",
+ "webExtension": {
+ "id": "web-experimental@ext"
+ }
+ }, {
+ "included": {
+ "everywhere": true
+ },
+ "webExtension": {
+ "id": "web-gb@ext"
+ }
+ }]
+ }
+
+Engine Defaults
+===============
+
+An engine may be specified as the default for one of two purposes:
+
+#. normal browsing mode,
+#. private browsing mode.
+
+If there is no engine specified for private browsing mode for a particular region/locale
+pair, then the normal mode engine is used.
+
+If the instance of the application does not support a separate private browsing mode engine,
+then it will only use the normal mode engine.
+
+An engine may or may not be default for particular regions/locales. The ``default``
+property is a tri-state value with states of ``yes``, ``yes-if-no-other`` and
+``no``. Here's an example of how they apply:
+
+.. code-block:: js
+
+ {
+ "webExtension": {
+ "id": "engine1@ext"
+ },
+ "appliesTo": [{
+ "included": {
+ "region": "us"
+ },
+ "default": "yes"
+ }, {
+ "excluded": {
+ "region": "us"
+ },
+ "default": "yes-if-no-other"
+ }]
+ },
+ {
+ "webExtension": {
+ "id": "engine2@ext"
+ },
+ "appliesTo": [{
+ "included": {
+ "region": "gb"
+ },
+ "default": "yes"
+ }]
+ },
+ "webExtension": {
+ "id": "engine3@ext"
+ },
+ "default": "no"
+ "appliesTo": [{
+ "included": {
+ "everywhere": true
+ },
+ }]
+ },
+ {
+ "webExtension": {
+ "id": "engine4@ext"
+ },
+ "defaultPrivate": "yes",
+ "appliesTo": [{
+ "included": {
+ "region": "fr"
+ }
+ }]
+ }
+
+In this example, for normal mode:
+
+ - engine1@ext is default in the US region, and all other regions except for GB
+ - engine2@ext is default in only the GB region
+ - engine3@ext and engine4 are never default anywhere
+
+In private browsing mode:
+
+ - engine1@ext is default in the US region, and all other regions except for GB and FR
+ - engine2@ext is default in only the GB region
+ - engine3@ext is never default anywhere
+ - engine4@ext is default in the FR region.
+
+Engine Ordering
+===============
+
+The ``orderHint`` field indicates the suggested ordering of an engine relative to
+other engines when displayed to the user, unless the user has customized their
+ordering.
+
+The default ordering of engines is based on a combination of if the engine is
+default, and the ``orderHint`` fields. The ordering is structured as follows:
+
+#. Default engine in normal mode
+#. Default engine in private browsing mode (if different from the normal mode engine)
+#. Other engines in order from the highest ``orderHint`` to the lowest.
+
+Example:
+
+.. code-block:: js
+
+ {
+ "webExtension": {
+ "id": "engine1@ext"
+ },
+ "orderHint": 2000,
+ "default": "no",
+ },
+ {
+ "webExtension": {
+ "id": "engine2@ext"
+ },
+ "orderHint": 1000,
+ "default": "yes"
+ },
+ {
+ "webExtension": {
+ "id": "engine3@ext"
+ },
+ "orderHint": 500,
+ "default": "no"
+ }
+
+This would result in the order: ``engine2@ext, engine1@ext, engine3@ext``.
+
+.. _schema itself: https://searchfox.org/mozilla-central/source/toolkit/components/search/schema/
+.. _the version comparator: https://developer.mozilla.org/en-US/docs/Mozilla/Toolkit_version_format
diff --git a/toolkit/components/search/docs/SearchEngines.rst b/toolkit/components/search/docs/SearchEngines.rst
index 9993abf8c6..58f45d580f 100644
--- a/toolkit/components/search/docs/SearchEngines.rst
+++ b/toolkit/components/search/docs/SearchEngines.rst
@@ -1,69 +1,44 @@
==============
Search Engines
==============
-This document describes the three main ways Firefox serves search engines to the
-user, enabling users to search the internet with different search providers.
-The three main ways Firefox serves search engines to the users is through:
+This document describes the four main type of search engines the Firefox
+serves to the user, enabling users to search the internet with different
+search providers. The types of search engines are:
+- Application Provided Search Engines
- Add-on Search Engines
-- OpenSearch Engines
+- Open Search Engines
- Enterprise Policy Engines
-An example of a search provider is Google, which is one of the Add-on Search
-Engines described in the first section below. Another example of a search
-provider is Bugzilla, which is an OpenSearch Engine described in the second
-section below. Lastly, there are Enterprise Policy Search Engines,
-which will be the third section described in this documentation.
+These are all represented by `similarly named classes`_ which inherit from
+the ``SearchEngine`` class and implement the :searchfox:`nsISearchEngine.idl <toolkit/components/search/nsISearchService.idl>`
+interface.
+
+Application Provided Search Engines
+===================================
+Application Provided Search Engines are engines provided by the application to
+the user as part of the configuration for the user's locale and region.
+These engines are managed through the `Search Configuration`_ file hosted on Remote Settings.
Add-on Search Engines
=====================
-Add-ons are additional functionality that third-party developers provide for
-users to install into Firefox. The add-on mechanism is also used by Firefox to
-ship the search engines provided by the application. To define Add-on Search
-Engines, developers use the `WebExtensions API`_. Since the WebExtensions API
-technology is used, developers interchangeably used the term WebExtension Search
-Engines when referring to Add-ons Search Engines.
-
-.. _WebExtensions API:
- https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions
-
-The list of Add-on Search Engines provided by Firefox and their extension files
-can be found in `mozilla-central/browser/components/search/extensions
-<https://searchfox.org/mozilla-central/source/browser/components/search/extensions>`__.
-Within each Add-on Search Engine folder, there is a manifest.json file. One of the
-keys in that manifest.json file is `chrome_settings_overrides`, whose value is an object
-that describes how to construct the url, images, strings, icon, etc. Here’s an example of
-how the search provider is set within `chrome_settings_overrides`:
-
-.. code-block:: js
-
- "chrome_settings_overrides": {
- "search_provider": {
- "name": "Discogs",
- "search_url": "https://www.discogs.com/search/?q={searchTerms}",
- "keyword": "disc",
- "favicon_url": "https://www.discogs.com/favicon.ico"
- }
- }
-
-
-To see more details on the syntax and properties, visit the `chrome settings
-overrides MDN documentation.
-<https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/
-manifest.json/chrome_settings_overrides>`__
+Users can install Add-on Search Engines into Firefox. Add-ons are additional
+functionality that third-party developers provide for users.
+
+To define Add-on Search Engines, developers use the `WebExtensions API`_,
+specifically the `chrome_settings_overrides`_ manifest key.
+
+Since the WebExtensions API technology is used, developers interchangeably used
+the term WebExtension Search Engines when referring to Add-ons Search Engines.
+
In Practice
-----------
All versions of Firefox support add-ons. Firefox switched over from OpenSearch
-to Add-on Search Engines internally in Firefox version 78. Add-on Search engines
-allows Firefox developers to have more flexibility and control in the
-modification of formatting search engines as we support different search
-providers.
-
-We maintain these Add-on Search Engines through a search configuration file that
-is bundled and configured via Remote Settings. As of this writing, June 2022, we
-use Remote Settings for managing search engines only for Firefox Desktop but not
-outside of Firefox Desktop.
+to Add-on Search Engines internally in Firefox version 78. We no longer ship
+Application Provided Search Engines through web extensions and switched to
+managing these engines via Remote Settings in Firefox version 126,
+as of April 22, 2024.
OpenSearch Engines
===================
@@ -81,9 +56,8 @@ is it allows site owners to easily provide users with a way to search a site.
History
-------
-Prior to OpenSearch, search plugins were first created by the `Mycroft Project
-<https://mycroftproject.com/>`__ and based off of `Sherlock
-<https://en.wikipedia.org/wiki/Sherlock_(software)>`__, a file and web search
+Prior to OpenSearch, search plugins were first created by the `Mycroft Project`_
+and based off of `Sherlock`_, a file and web search
tool created by Apple.
The OpenSearch Protocol was created and launched by A9.com in 2005. OpenSearch
@@ -91,8 +65,7 @@ was added to Firefox version 2 in the year 2006. As of today in 2022, OpenSearch
is a collection of formats for sharing of search results. The code is stable but
unchanged for many years.
-See the `OpenSearch Documentation <https://github.com/dewitt/opensearch>`__ for
-more information on the OpenSearch formats.
+See the `OpenSearch Documentation`_ for more information on the OpenSearch formats.
Autodiscovery
-------------
@@ -118,9 +91,7 @@ Bugzilla icon to make a search directly on bugzilla.mozilla.org.
:scale: 28%
:align: center
-See the `Autodiscovery MDN Documentation <https://developer.mozilla.org/en-US/
-docs/Web/OpenSearch#autodiscovery_of_search_plugins>`__ for more information on
-Autodiscovery.
+See the `Autodiscovery MDN Documentation`_ for more information on Autodiscovery.
Enterprise Policy Engines
=========================
@@ -132,18 +103,13 @@ configuration that was set in place.
Enterprise Policy Engines are search engines that a company has added as search
engines on Firefox for their users by setting the Enterprise Policy. In this
-`Enterprise Policy Documentation
-<https://mozilla.github.io/policy-templates/#searchengines
--this-policy-is-only-available-on-the-esr>`__,
-it outlines the different options that are available for enterprises using
-Firefox ESR (Extended Support Release) and what’s available in terms of adding,
-updating, or removing search engines. The company can use the policy to define
-which search engines are available on their Firefox ESR.
-
-See the `policy-templates
-<https://mozilla.github.io/policy-templates/>`__ for more
-information on Enterprise Policy templates and the different configuration rules
-available.
+`Enterprise Policy Documentation`_ it outlines the different options that are
+available for enterprises using Firefox ESR (Extended Support Release) and what’s
+available in terms of adding, updating, or removing search engines. The company
+can use the policy to define which search engines are available on their Firefox ESR.
+
+See the `policy-templates`_ for more information on Enterprise Policy templates
+and the different configuration rules available.
Configuration
-------------
@@ -152,11 +118,8 @@ depending on which operating system their machines are on. The admin can
configure the policy on a server and when the user logs in, those configurations
are automatically pushed to the user’s Firefox.
-For Windows, the `GPO (Group Policy Object)
-<https://github.com/mozilla/policy-templates/tree/master/windows>`__ or `Intune
-(Microsoft Endpoint Manager) <https://support.mozilla.org/en-US/kb/managing-firefox-intune>`__ is
-used to set the policy. For macOS, `configuration profiles
-<https://github.com/mozilla/policy-templates/tree/master/mac>`__ are created.
+For Windows, the `GPO (Group Policy Object)`_ or `Intune (Microsoft Endpoint Manager)`_ is
+used to set the policy. For macOS, `configuration profiles`_ are created.
For the generic case, there is a JSON file to describe the policy.
When these configurations are set, Firefox takes the configuration as inputs and
@@ -195,3 +158,17 @@ Firefox will find it and Firefox will open and run with the policy.
Common formatting mistakes are often made when creating the JSON file. The JSON
file can be validated using a JSON validator such as https://jsonlint.com/.
+
+.. _similarly named classes: https://searchfox.org/mozilla-central/search?q=&path=toolkit%2Fcomponents%2Fsearch%2F*SearchEngine.sys.mjs
+.. _Search Configuration: SearchConfigurationSchema.html
+.. _WebExtensions API: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions
+.. _chrome_settings_overrides: https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/manifest.json/chrome_settings_overrides
+.. _Sherlock: https://en.wikipedia.org/wiki/Sherlock_(software)
+.. _Mycroft Project: https://mycroftproject.com/
+.. _OpenSearch Documentation: https://github.com/dewitt/opensearch
+.. _Autodiscovery MDN Documentation: https://developer.mozilla.org/en-US/docs/Web/OpenSearch#autodiscovery_of_search_plugins
+.. _Enterprise Policy Documentation: https://mozilla.github.io/policy-templates/#searchengines-this-policy-is-only-available-on-the-esr
+.. _policy-templates: https://mozilla.github.io/policy-templates/
+.. _GPO (Group Policy Object): https://github.com/mozilla/policy-templates/tree/master/windows
+.. _Intune (Microsoft Endpoint Manager): https://support.mozilla.org/en-US/kb/managing-firefox-intune
+.. _configuration profiles: https://github.com/mozilla/policy-templates/tree/master/mac
diff --git a/toolkit/components/search/docs/SearchEnginesArchive.rst b/toolkit/components/search/docs/SearchEnginesArchive.rst
new file mode 100644
index 0000000000..31ce4fff4a
--- /dev/null
+++ b/toolkit/components/search/docs/SearchEnginesArchive.rst
@@ -0,0 +1,197 @@
+=========================
+Search Engines (Archived)
+=========================
+This document describes the three main ways Firefox serves search engines to the
+user, enabling users to search the internet with different search providers.
+The three main ways Firefox serves search engines to the users is through:
+
+- Add-on Search Engines
+- OpenSearch Engines
+- Enterprise Policy Engines
+
+An example of a search provider is Google, which is one of the Add-on Search
+Engines described in the first section below. Another example of a search
+provider is Bugzilla, which is an OpenSearch Engine described in the second
+section below. Lastly, there are Enterprise Policy Search Engines,
+which will be the third section described in this documentation.
+
+Add-on Search Engines
+=====================
+Add-ons are additional functionality that third-party developers provide for
+users to install into Firefox. The add-on mechanism is also used by Firefox to
+ship the search engines provided by the application. To define Add-on Search
+Engines, developers use the `WebExtensions API`_. Since the WebExtensions API
+technology is used, developers interchangeably used the term WebExtension Search
+Engines when referring to Add-ons Search Engines.
+
+.. _WebExtensions API:
+ https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions
+
+The list of Add-on Search Engines provided by Firefox and their extension files
+can be found in `mozilla-central/browser/components/search/extensions
+<https://searchfox.org/mozilla-central/source/browser/components/search/extensions>`__.
+Within each Add-on Search Engine folder, there is a manifest.json file. One of the
+keys in that manifest.json file is `chrome_settings_overrides`, whose value is an object
+that describes how to construct the url, images, strings, icon, etc. Here’s an example of
+how the search provider is set within `chrome_settings_overrides`:
+
+.. code-block:: js
+
+ "chrome_settings_overrides": {
+ "search_provider": {
+ "name": "Discogs",
+ "search_url": "https://www.discogs.com/search/?q={searchTerms}",
+ "keyword": "disc",
+ "favicon_url": "https://www.discogs.com/favicon.ico"
+ }
+ }
+
+
+To see more details on the syntax and properties, visit the `chrome settings
+overrides MDN documentation.
+<https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/
+manifest.json/chrome_settings_overrides>`__
+
+In Practice
+-----------
+All versions of Firefox support add-ons. Firefox switched over from OpenSearch
+to Add-on Search Engines internally in Firefox version 78. Add-on Search engines
+allows Firefox developers to have more flexibility and control in the
+modification of formatting search engines as we support different search
+providers.
+
+We maintain these Add-on Search Engines through a search configuration file that
+is bundled and configured via Remote Settings. As of this writing, June 2022, we
+use Remote Settings for managing search engines only for Firefox Desktop but not
+outside of Firefox Desktop.
+
+OpenSearch Engines
+===================
+OpenSearch is a plugin, software installed on Firefox to enhance capabilities
+for searching. OpenSearch has a collection of formats that describe how to
+construct the url, images, strings, icon, etc. These formats provided by
+OpenSearch allow Firefox to make a search over the internet with a specific
+search provider that is not an application provided search engine on Firefox.
+The purpose of OpenSearch is to provide more convenient ways of searching and
+different ways of searching.
+
+OpenSearch allows users to search with a vast variety of search providers which
+do not come installed with Firefox out of the box. The main benefit of OpenSearch
+is it allows site owners to easily provide users with a way to search a site.
+
+History
+-------
+Prior to OpenSearch, search plugins were first created by the `Mycroft Project
+<https://mycroftproject.com/>`__ and based off of `Sherlock
+<https://en.wikipedia.org/wiki/Sherlock_(software)>`__, a file and web search
+tool created by Apple.
+
+The OpenSearch Protocol was created and launched by A9.com in 2005. OpenSearch
+was added to Firefox version 2 in the year 2006. As of today in 2022, OpenSearch
+is a collection of formats for sharing of search results. The code is stable but
+unchanged for many years.
+
+See the `OpenSearch Documentation <https://github.com/dewitt/opensearch>`__ for
+more information on the OpenSearch formats.
+
+Autodiscovery
+-------------
+Autodiscovery is a feature on Firefox which automatically notifies the user when
+the webpage they visited has a search plugin.
+
+Here is an example of Autodiscovery from Bugzilla. You can visit
+https://bugzilla.mozilla.org and Firefox will automatically detect that the
+website has a provided search plugin. In the results dropdown, you can look at
+the search engine shortcuts section at the bottom and it will show a green plus
+sign over the Bugzilla search icon. The green plus sign indicates that the user
+can add Bugzilla as an OpenSearch Engine. After the user adds Bugzilla as an
+OpenSearch Engine, the green plus icon disappears. The user can now click the
+Bugzilla icon to make a search directly on bugzilla.mozilla.org.
+
+.. figure:: assets/bugzilla-open-search1.png
+ :alt: Image of the address bar input showing a URL
+ :scale: 28%
+ :align: center
+
+.. figure:: assets/bugzilla-open-search2.png
+ :alt: Image of the address bar input showing a URL
+ :scale: 28%
+ :align: center
+
+See the `Autodiscovery MDN Documentation <https://developer.mozilla.org/en-US/
+docs/Web/OpenSearch#autodiscovery_of_search_plugins>`__ for more information on
+Autodiscovery.
+
+Enterprise Policy Engines
+=========================
+Enterprise Policies are customizable configurations for the Firefox browser set
+by enterprises or companies who want to distribute configuration for their
+users. The idea of Enterprise Policies is to allow companies to customize Firefox
+and how their users can or cannot change the usage of Firefox based on predefined
+configuration that was set in place.
+
+Enterprise Policy Engines are search engines that a company has added as search
+engines on Firefox for their users by setting the Enterprise Policy. In this
+`Enterprise Policy Documentation
+<https://mozilla.github.io/policy-templates/#searchengines
+-this-policy-is-only-available-on-the-esr>`__,
+it outlines the different options that are available for enterprises using
+Firefox ESR (Extended Support Release) and what’s available in terms of adding,
+updating, or removing search engines. The company can use the policy to define
+which search engines are available on their Firefox ESR.
+
+See the `policy-templates
+<https://mozilla.github.io/policy-templates/>`__ for more
+information on Enterprise Policy templates and the different configuration rules
+available.
+
+Configuration
+-------------
+In practice, there are different ways for a company to specify their policy,
+depending on which operating system their machines are on. The admin can
+configure the policy on a server and when the user logs in, those configurations
+are automatically pushed to the user’s Firefox.
+
+For Windows, the `GPO (Group Policy Object)
+<https://github.com/mozilla/policy-templates/tree/master/windows>`__ or `Intune
+(Microsoft Endpoint Manager) <https://support.mozilla.org/en-US/kb/managing-firefox-intune>`__ is
+used to set the policy. For macOS, `configuration profiles
+<https://github.com/mozilla/policy-templates/tree/master/mac>`__ are created.
+For the generic case, there is a JSON file to describe the policy.
+
+When these configurations are set, Firefox takes the configuration as inputs and
+turns them into settings that Firefox can consume.
+
+A Hypothetical Use of Enterprise Policy
+---------------------------------------
+A company that is in the banking industry and requires tighter security over
+their users may not want their users to do something on Firefox without the
+company's knowledge. It may make sense for the company to disable private
+browsing for Firefox.
+
+Within a specific company, the employees of the finance department could use the
+Firefox ESR version. In this situation, we think of the finance department as
+the Firefox user rather than the individual employees as Firefox users. The
+department makes choices for the individuals that use the Firefox browser
+through the Enterprise Policy.
+
+Features On Enterprise Policy
+-----------------------------
+All Firefox versions have to honor the Enterprise Policy, but the Enterprise
+Policy may not have effect on an individual who is not using Firefox ESR at a
+company. There are features that are enterprise specific that are only available
+in ESR. These features allow search engines to be configured, allowing for
+unsigned extensions, installing search engines, and setting a default search
+engine.
+
+How To Set Up and Use an Enterprise Policy for Firefox
+------------------------------------------------------
+Install the ESR version of Firefox since Enterprise Policies are not supported on
+rapid release. Then, create the JSON file that is located in the README.md within
+https://github.com/mozilla/policy-templates. There are instructions there on how
+to configure and use the policy. Once the JSON is created with the appropriate
+settings, drop the JSON file in the directory outlined by the README.md and
+Firefox will find it and Firefox will open and run with the policy.
+
+Common formatting mistakes are often made when creating the JSON file. The JSON
+file can be validated using a JSON validator such as https://jsonlint.com/.
diff --git a/toolkit/components/search/docs/SearchServiceHighlevelOverview.rst b/toolkit/components/search/docs/SearchServiceHighlevelOverview.rst
index 1701f3a52b..36b76a9a6f 100644
--- a/toolkit/components/search/docs/SearchServiceHighlevelOverview.rst
+++ b/toolkit/components/search/docs/SearchServiceHighlevelOverview.rst
@@ -19,8 +19,8 @@ overview of the main components the ``SearchService`` interacts with most often.
Diagram
=======
-.. figure:: assets/search-service-diagram.png
- :scale: 85%
+.. figure:: assets/search-service-diagram-2.png
+ :scale: 30%
:align: center
Description of the Diagram
@@ -30,39 +30,33 @@ described by number 1 below.
1. When the user opens the Firefox Browser, the code starts to build the browser
UI components. During this startup phase, we have various systems making
- calls to the ``SearchService``. E.g. `browser.js <https://searchfox.org/mozilla-central/rev/cb6f8d7b1f1782b9d4b2ee7312de1dcc284aaf06/browser/base/content/browser.js#3797>`_
+ calls to the ``SearchService``. E.g. `browser.js <https://searchfox.org/mozilla-central/rev/47db1be98f8069b387ce07dcbea22d09f1854515/browser/base/content/browser.js#3325>`_
calls ``Services.search.getDefault`` to fetch the default Search Engine.
-2. The ``SearchService`` needs information from ``System Add-ons``,
+2. The ``SearchService`` needs information from ``Extension System``,
``SearchSettings``, and ``Remote Settings`` to build the correct engines in
the right order and to return the list of engines to its callers.
a) First, the ``SearchService`` makes a request for the search configuration.
- ``SearchService`` calls `SearchEngineSelector.fetchEngineConfiguration <https://searchfox.org/mozilla-central/rev/cb6f8d7b1f1782b9d4b2ee7312de1dcc284aaf06/toolkit/components/search/SearchService.sys.mjs#2247>`_
- which makes a call to `Remote Settings <https://searchfox.org/mozilla-central/rev/cb6f8d7b1f1782b9d4b2ee7312de1dcc284aaf06/toolkit/components/search/SearchEngineSelector.sys.mjs#129>`_
+ ``SearchService`` calls `SearchEngineSelector.fetchEngineConfiguration <https://searchfox.org/mozilla-central/rev/47db1be98f8069b387ce07dcbea22d09f1854515/toolkit/components/search/SearchService.sys.mjs#2602>`_
+ which makes a call to `Remote Settings <https://searchfox.org/mozilla-central/rev/47db1be98f8069b387ce07dcbea22d09f1854515/toolkit/components/search/SearchEngineSelector.sys.mjs#119>`_
for the search configuration. Remote Settings does not fetch the search
configuration from the remote database on startup. Instead Remote Settings
- tries to load the :searchfox:`search configuration dump file <services/settings/dumps/main/search-config.json>`
+ tries to load the :searchfox:`search configuration dump file <services/settings/dumps/main/search-config-v2.json>`
from its local database and if that is empty, it will load the dump file into
its local database. Only after startup will Remote Settings connect to the
remote database when necessary. By connecting after startup, it avoids
a potential network request that could delay startup.
- b) Second, the ``SearchService`` `fetches a JSON file <https://searchfox.org/mozilla-central/rev/cb6f8d7b1f1782b9d4b2ee7312de1dcc284aaf06/toolkit/components/search/SearchService.sys.mjs#1296-1297>`_
+ b) Second, the ``SearchService`` `fetches a JSON file <https://searchfox.org/mozilla-central/rev/47db1be98f8069b387ce07dcbea22d09f1854515/toolkit/components/search/SearchService.sys.mjs#1368>`_
from the `SearchSettings <https://searchfox.org/mozilla-central/source/toolkit/components/search/SearchSettings.sys.mjs>`_.
This JSON file contains Search Engine metadata that is saved on the user's
computer. It's information that helps the ``SearchService`` remember the
user's custom settings for the Search Engines.
- c) Third, the `System Add-ons <https://searchfox.org/mozilla-central/rev/cb6f8d7b1f1782b9d4b2ee7312de1dcc284aaf06/browser/components/extensions/parent/ext-chrome-settings-overrides.js#536>`_
+ c) Third, the `Extension System <https://searchfox.org/mozilla-central/rev/cb6f8d7b1f1782b9d4b2ee7312de1dcc284aaf06/browser/components/extensions/parent/ext-chrome-settings-overrides.js#536>`_
passes the extension data to the ``SearchService``. At this point, the
- ``SearchService`` only installs user installed search extensions. For the
- Application Provided engines we create those when ``SearchService`` calls `_makeEngineFromConfig <https://searchfox.org/mozilla-central/rev/3002762e41363de8ee9ca80196d55e79651bcb6b/toolkit/components/search/SearchService.sys.mjs#3421-3440>`_.
- Then ``_makeEngineFromConfig`` will create a new ``AddonSearchEngine``.
- When the `AddonSearchEngine.init <https://searchfox.org/mozilla-central/rev/3002762e41363de8ee9ca80196d55e79651bcb6b/toolkit/components/search/AddonSearchEngine.sys.mjs#83-87,89>`_
- method is called, it combines both the extension and search configuration
- data to create the correct engine for the user based on locale, region and
- other information.
+ ``SearchService`` only installs user installed search extensions.
After steps 2a, 2b, and 2c the ``SearchService`` has finished gathering
search engine data from ``System Add-ons``, ``SearchSettings``, and
@@ -70,7 +64,7 @@ described by number 1 below.
types of Search Engines.
3. The ``SearchService`` creates new instances of :searchfox:`SearchEngines <toolkit/components/search/SearchEngine.sys.mjs>`
- by making an `Add-on, Open Search, or Enterprise Policy Search Engine <https://firefox-source-docs.mozilla.org/toolkit/search/SearchEngines.html>`_.
+ by making an `App-Provided, Add-on, Open Search, or Enterprise Policy Search Engine <https://firefox-source-docs.mozilla.org/toolkit/search/SearchEngines.html>`_.
4. The ``SearchService`` returns the engines to the caller that requested it.
E.g. the ``SearchService`` passes the default Search Engine back to
@@ -78,8 +72,7 @@ described by number 1 below.
Updates
=======
-This page is up to date as of March 10, 2023. If the diagram or description
-becomes out of date, please find access to the
-``Search Service Diagram`` through the ``Firefox Search > Search Service
-Documentation`` folder in the shared drive or through this link `here <https://drive.google.com/file/d/1vKRRK87kIGt6xamHJuclkC04EKrS69Qw/view?usp=sharing>`_.
-Contributions are welcomed to keep this page up to date.
+This page is up to date as of April 18, 2024. If the diagram or description
+becomes out of date, please find access to the ``Search Service Diagram`` in
+``Firefox Search > Search Service Documentation`` folder in the Firefox Search
+shared drive. Contributions are welcomed to keep this page up to date.
diff --git a/toolkit/components/search/docs/SearchServiceHighlevelOverviewArchive.rst b/toolkit/components/search/docs/SearchServiceHighlevelOverviewArchive.rst
new file mode 100644
index 0000000000..a409a37ed4
--- /dev/null
+++ b/toolkit/components/search/docs/SearchServiceHighlevelOverviewArchive.rst
@@ -0,0 +1,85 @@
+============================================
+SearchService High-level Overview (Archived)
+============================================
+``SearchService`` is the core component that manages Search Engines on the
+Firefox browser.
+
+The following diagram is a high level systems context diagram of the
+``SearchService``. The diagram illustrates which systems interface with the
+``SearchService`` so that it can do its job of managing the Search Engines.
+
+The diagram and description is an over-simplification of the ``SearchService's``
+responsibilities. It specifically highlights how the ``SearchService`` serves
+search engines to the browser on startup. However, the ``SearchService`` has
+many other responsibilities that are not outlined in the diagram such as
+maintaining and managing the Search Engines when various items change, e.g. the
+user's region or locale, configuration changes received from remote settings,
+updates received to search engine data. Nonetheless, the diagram gives a broad
+overview of the main components the ``SearchService`` interacts with most often.
+
+Diagram
+=======
+.. figure:: assets/search-service-diagram-1.png
+ :scale: 85%
+ :align: center
+
+Description of the Diagram
+==========================
+These steps follow the same number on the diagram. Number 1 on the diagram is
+described by number 1 below.
+
+1. When the user opens the Firefox Browser, the code starts to build the browser
+ UI components. During this startup phase, we have various systems making
+ calls to the ``SearchService``. E.g. `browser.js <https://searchfox.org/mozilla-central/rev/cb6f8d7b1f1782b9d4b2ee7312de1dcc284aaf06/browser/base/content/browser.js#3797>`_
+ calls ``Services.search.getDefault`` to fetch the default Search Engine.
+
+2. The ``SearchService`` needs information from ``System Add-ons``,
+ ``SearchSettings``, and ``Remote Settings`` to build the correct engines in
+ the right order and to return the list of engines to its callers.
+
+ a) First, the ``SearchService`` makes a request for the search configuration.
+ ``SearchService`` calls `SearchEngineSelector.fetchEngineConfiguration <https://searchfox.org/mozilla-central/rev/cb6f8d7b1f1782b9d4b2ee7312de1dcc284aaf06/toolkit/components/search/SearchService.sys.mjs#2247>`_
+ which makes a call to `Remote Settings <https://searchfox.org/mozilla-central/rev/cb6f8d7b1f1782b9d4b2ee7312de1dcc284aaf06/toolkit/components/search/SearchEngineSelector.sys.mjs#129>`_
+ for the search configuration. Remote Settings does not fetch the search
+ configuration from the remote database on startup. Instead Remote Settings
+ tries to load the :searchfox:`search configuration dump file <services/settings/dumps/main/search-config.json>`
+ from its local database and if that is empty, it will load the dump file into
+ its local database. Only after startup will Remote Settings connect to the
+ remote database when necessary. By connecting after startup, it avoids
+ a potential network request that could delay startup.
+
+ b) Second, the ``SearchService`` `fetches a JSON file <https://searchfox.org/mozilla-central/rev/cb6f8d7b1f1782b9d4b2ee7312de1dcc284aaf06/toolkit/components/search/SearchService.sys.mjs#1296-1297>`_
+ from the `SearchSettings <https://searchfox.org/mozilla-central/source/toolkit/components/search/SearchSettings.sys.mjs>`_.
+ This JSON file contains Search Engine metadata that is saved on the user's
+ computer. It's information that helps the ``SearchService`` remember the
+ user's custom settings for the Search Engines.
+
+ c) Third, the `System Add-ons <https://searchfox.org/mozilla-central/rev/cb6f8d7b1f1782b9d4b2ee7312de1dcc284aaf06/browser/components/extensions/parent/ext-chrome-settings-overrides.js#536>`_
+ passes the extension data to the ``SearchService``. At this point, the
+ ``SearchService`` only installs user installed search extensions. For the
+ Application Provided engines we create those when ``SearchService`` calls `_makeEngineFromConfig <https://searchfox.org/mozilla-central/rev/3002762e41363de8ee9ca80196d55e79651bcb6b/toolkit/components/search/SearchService.sys.mjs#3421-3440>`_.
+ Then ``_makeEngineFromConfig`` will create a new ``AddonSearchEngine``.
+ When the `AddonSearchEngine.init <https://searchfox.org/mozilla-central/rev/3002762e41363de8ee9ca80196d55e79651bcb6b/toolkit/components/search/AddonSearchEngine.sys.mjs#83-87,89>`_
+ method is called, it combines both the extension and search configuration
+ data to create the correct engine for the user based on locale, region and
+ other information.
+
+ After steps 2a, 2b, and 2c the ``SearchService`` has finished gathering
+ search engine data from ``System Add-ons``, ``SearchSettings``, and
+ ``Remote Settings``. Now the ``SearchService`` can build the different
+ types of Search Engines.
+
+3. The ``SearchService`` creates new instances of :searchfox:`SearchEngines <toolkit/components/search/SearchEngine.sys.mjs>`
+ by making an `Add-on, Open Search, or Enterprise Policy Search Engine <https://firefox-source-docs.mozilla.org/toolkit/search/SearchEngines.html>`_.
+
+4. The ``SearchService`` returns the engines to the caller that requested it.
+ E.g. the ``SearchService`` passes the default Search Engine back to
+ ``browser.js``, the system that initially requested it.
+
+Updates
+=======
+This page is up to date as of March 10, 2023. If the diagram or description
+becomes out of date, please find access to the
+``Search Service Diagram`` through the ``Firefox Search > Search Service
+Documentation`` folder in the shared drive or through this link `here <https://drive.google.com/file/d/1vKRRK87kIGt6xamHJuclkC04EKrS69Qw/view?usp=sharing>`_.
+Contributions are welcomed to keep this page up to date.
diff --git a/toolkit/components/search/docs/assets/search-service-diagram.png b/toolkit/components/search/docs/assets/search-service-diagram-1.png
index cdd244b8f4..cdd244b8f4 100644
--- a/toolkit/components/search/docs/assets/search-service-diagram.png
+++ b/toolkit/components/search/docs/assets/search-service-diagram-1.png
Binary files differ
diff --git a/toolkit/components/search/docs/assets/search-service-diagram-2.png b/toolkit/components/search/docs/assets/search-service-diagram-2.png
new file mode 100644
index 0000000000..4024807a40
--- /dev/null
+++ b/toolkit/components/search/docs/assets/search-service-diagram-2.png
Binary files differ
diff --git a/toolkit/components/search/docs/index.rst b/toolkit/components/search/docs/index.rst
index 10ae8118bf..566b15943d 100644
--- a/toolkit/components/search/docs/index.rst
+++ b/toolkit/components/search/docs/index.rst
@@ -38,7 +38,10 @@ Contents for search-config (archived)
.. toctree::
:maxdepth: 2
+ SearchServiceHighlevelOverviewArchive
SearchEngineConfigurationArchive
+ SearchConfigurationSchemaArchive
+ SearchEnginesArchive
API Reference
-------------
diff --git a/toolkit/components/search/tests/xpcshell/searchconfigs/test_ebay.js b/toolkit/components/search/tests/xpcshell/searchconfigs/test_ebay.js
index ed8e5147ee..8162fffae8 100644
--- a/toolkit/components/search/tests/xpcshell/searchconfigs/test_ebay.js
+++ b/toolkit/components/search/tests/xpcshell/searchconfigs/test_ebay.js
@@ -56,6 +56,9 @@ const test = new SearchConfigTest({
],
},
{
+ regions: ["pl"],
+ },
+ {
regions: ["au", "be", "ca", "ch", "gb", "ie", "nl", "us"],
locales: ["en-US"],
},
@@ -79,6 +82,7 @@ const test = new SearchConfigTest({
locales: ["br", "unknown", "en-US", "fr", "fy-NL", "nl", "wo"],
},
],
+ excluded: [{ regions: ["pl"] }],
searchUrlCode: "mkrid=1553-53471-19255-0",
suggestUrlCode: "sId=23",
},
@@ -91,6 +95,7 @@ const test = new SearchConfigTest({
locales: ["de", "dsb", "hsb"],
},
],
+ excluded: [{ regions: ["pl"] }],
searchUrlCode: "mkrid=5221-53469-19255-0",
suggestUrlCode: "sId=16",
},
@@ -117,6 +122,9 @@ const test = new SearchConfigTest({
...DOMAIN_LOCALES["ebay-uk"],
],
},
+ {
+ regions: ["pl"],
+ },
],
searchUrlCode: "mkrid=706-53473-19255-0",
suggestUrlCode: "sId=2",
@@ -143,6 +151,9 @@ const test = new SearchConfigTest({
...DOMAIN_LOCALES["ebay-uk"],
],
},
+ {
+ regions: ["pl"],
+ },
],
searchUrlCode: "mkrid=5222-53480-19255-0",
suggestUrlCode: "sId=193",
@@ -155,7 +166,7 @@ const test = new SearchConfigTest({
locales: ["unknown", "en-US"],
},
],
- excluded: [{ regions: ["au", "be", "ca", "ch", "gb", "ie", "nl"] }],
+ excluded: [{ regions: ["au", "be", "ca", "ch", "gb", "ie", "nl", "pl"] }],
searchUrlCode: "mkrid=711-53200-19255-0",
suggestUrlCode: "sId=0",
},
@@ -168,6 +179,7 @@ const test = new SearchConfigTest({
locales: ["cy", "unknown", "en-GB", "en-US", "gd"],
},
],
+ excluded: [{ regions: ["pl"] }],
searchUrlCode: "mkrid=705-53470-19255-0",
suggestUrlCode: "sId=15",
},
@@ -183,6 +195,7 @@ const test = new SearchConfigTest({
locales: ["cy", "unknown", "en-GB", "en-US", "gd"],
},
],
+ excluded: [{ regions: ["pl"] }],
searchUrlCode: "mkrid=5282-53468-19255-0",
suggestUrlCode: "sId=205",
},
@@ -198,7 +211,7 @@ const test = new SearchConfigTest({
regions: ["gb"],
},
],
- excluded: [{ regions: ["au", "ie"] }],
+ excluded: [{ regions: ["au", "ie", "pl"] }],
searchUrlCode: "mkrid=710-53481-19255-0",
suggestUrlCode: "sId=3",
},
@@ -210,7 +223,7 @@ const test = new SearchConfigTest({
locales: DOMAIN_LOCALES["ebay-de"],
},
],
- excluded: [{ regions: ["at", "ch"] }],
+ excluded: [{ regions: ["at", "ch", "pl"] }],
searchUrlCode: "mkrid=707-53477-19255-0",
suggestUrlCode: "sId=77",
},
@@ -222,6 +235,7 @@ const test = new SearchConfigTest({
locales: DOMAIN_LOCALES["ebay-es"],
},
],
+ excluded: [{ regions: ["pl"] }],
searchUrlCode: "mkrid=1185-53479-19255-0",
suggestUrlCode: "sId=186",
},
@@ -233,7 +247,7 @@ const test = new SearchConfigTest({
locales: ["br", "fr", "wo"],
},
],
- excluded: [{ regions: ["be", "ca", "ch"] }],
+ excluded: [{ regions: ["be", "ca", "ch", "pl"] }],
searchUrlCode: "mkrid=709-53476-19255-0",
suggestUrlCode: "sId=71",
},
@@ -245,6 +259,7 @@ const test = new SearchConfigTest({
locales: DOMAIN_LOCALES["ebay-it"],
},
],
+ excluded: [{ regions: ["pl"] }],
searchUrlCode: "mkrid=724-53478-19255-0",
suggestUrlCode: "sId=101",
},
@@ -260,10 +275,21 @@ const test = new SearchConfigTest({
regions: ["nl"],
},
],
- excluded: [{ regions: ["be"] }],
+ excluded: [{ regions: ["be", "pl"] }],
searchUrlCode: "mkrid=1346-53482-19255-0",
suggestUrlCode: "sId=146",
},
+ {
+ domain: "www.ebay.pl",
+ telemetryId: "ebay-pl",
+ included: [
+ {
+ regions: ["pl"],
+ },
+ ],
+ searchUrlCode: "mkrid=4908-226936-19255-0",
+ suggestUrlCode: "sId=212",
+ },
],
});
diff --git a/toolkit/components/search/tests/xpcshell/searchconfigs/xpcshell.toml b/toolkit/components/search/tests/xpcshell/searchconfigs/xpcshell.toml
index 07567005d6..3bd896173c 100644
--- a/toolkit/components/search/tests/xpcshell/searchconfigs/xpcshell.toml
+++ b/toolkit/components/search/tests/xpcshell/searchconfigs/xpcshell.toml
@@ -28,7 +28,14 @@ requesttimeoutfactor = 2
["test_duckduckgo.js"]
+# The test_ebay needs newSearchConfig.enabled=true because there
+# are changes to ebay and locale pl for search-config-v2.
+# We have rolled out search-config-v2 100% to Beta 126 and the next Beta 127
+# will pick up newSearchConfig.enabled=true from Nimbus Settings but not
+# immediately, we need to turn the PREF on for this test to prevent failures
+# in the merge from central to Beta 127.
["test_ebay.js"]
+prefs = ["browser.search.newSearchConfig.enabled=true"]
["test_ecosia.js"]
diff --git a/toolkit/components/search/tests/xpcshell/test_appProvided_engine.js b/toolkit/components/search/tests/xpcshell/test_appProvided_engine.js
index 56297a9d2c..c983bdd666 100644
--- a/toolkit/components/search/tests/xpcshell/test_appProvided_engine.js
+++ b/toolkit/components/search/tests/xpcshell/test_appProvided_engine.js
@@ -68,6 +68,33 @@ let CONFIG = [
variants: [{ environment: { allRegionsAndLocales: true } }],
},
{
+ identifier: "override",
+ recordType: "engine",
+ base: {
+ classification: "unknown",
+ name: "override name",
+ urls: {
+ search: {
+ base: "https://www.example.com/search",
+ params: [
+ {
+ name: "old_param",
+ value: "old_value",
+ },
+ ],
+ searchTermParamName: "q",
+ },
+ },
+ },
+ variants: [
+ {
+ environment: {
+ locales: ["en-US"],
+ },
+ },
+ ],
+ },
+ {
recordType: "defaultEngines",
globalDefault: "engine_no_initial_icon",
specificDefaults: [],
@@ -78,6 +105,19 @@ let CONFIG = [
},
];
+const TEST_CONFIG_OVERRIDE = [
+ {
+ identifier: "override",
+ urls: {
+ search: {
+ params: [{ name: "new_param", value: "new_value" }],
+ },
+ },
+ telemetrySuffix: "tsfx",
+ clickUrl: "https://example.org/somewhere",
+ },
+];
+
add_setup(async function () {
await SearchTestUtils.useTestEngines("simple-engines", null, CONFIG);
await Services.search.init();
@@ -180,3 +220,53 @@ add_task(async function test_engine_with_some_params_set() {
"Should not have a trending URL"
);
});
+
+add_task(async function test_engine_remote_override() {
+ // First check the existing engine doesn't have the overrides.
+ let engine = Services.search.getEngineById(
+ "override@search.mozilla.orgdefault"
+ );
+ Assert.ok(engine, "Should have found the override engine");
+
+ Assert.equal(engine.name, "override name", "Should have the expected name");
+ Assert.equal(
+ engine.telemetryId,
+ "override",
+ "Should have the overridden telemetry suffix"
+ );
+ Assert.equal(
+ engine.getSubmission("test").uri.spec,
+ "https://www.example.com/search?old_param=old_value&q=test",
+ "Should have the overridden URL"
+ );
+ Assert.equal(engine.clickUrl, null, "Should not have a click URL");
+
+ // Now apply and test the overrides.
+ const overrides = await RemoteSettings(
+ SearchUtils.NEW_SETTINGS_OVERRIDES_KEY
+ );
+ sinon.stub(overrides, "get").returns(TEST_CONFIG_OVERRIDE);
+
+ await Services.search.wrappedJSObject.reset();
+ await Services.search.init();
+
+ engine = Services.search.getEngineById("override@search.mozilla.orgdefault");
+ Assert.ok(engine, "Should have found the override engine");
+
+ Assert.equal(engine.name, "override name", "Should have the expected name");
+ Assert.equal(
+ engine.telemetryId,
+ "override-tsfx",
+ "Should have the overridden telemetry suffix"
+ );
+ Assert.equal(
+ engine.getSubmission("test").uri.spec,
+ "https://www.example.com/search?new_param=new_value&q=test",
+ "Should have the overridden URL"
+ );
+ Assert.equal(
+ engine.clickUrl,
+ "https://example.org/somewhere",
+ "Should have the click URL specified by the override"
+ );
+});
diff --git a/toolkit/components/search/tests/xpcshell/test_missing_engine.js b/toolkit/components/search/tests/xpcshell/test_missing_engine.js
index 259baf9c1a..496397790e 100644
--- a/toolkit/components/search/tests/xpcshell/test_missing_engine.js
+++ b/toolkit/components/search/tests/xpcshell/test_missing_engine.js
@@ -2,7 +2,8 @@
http://creativecommons.org/publicdomain/zero/1.0/ */
// This test is designed to check the search service keeps working if there's
-// a built-in engine missing from the configuration.
+// an application provided WebExtension missing that is referenced from the
+// configuration. Only applies to the old search configuration.
"use strict";
@@ -55,64 +56,16 @@ const BAD_CONFIG = [
},
];
-const CONFIG_V2 = [
- {
- recordType: "engine",
- identifier: "engine",
- base: {
- name: "Test search engine",
- urls: {
- search: {
- base: "https://www.google.com/search",
- params: [
- {
- name: "channel",
- searchAccessPoint: {
- addressbar: "fflb",
- contextmenu: "rcs",
- },
- },
- ],
- searchTermParamName: "q",
- },
- suggestions: {
- base: "https://suggestqueries.google.com/complete/search?output=firefox&client=firefox&hl={moz:locale}",
- searchTermParamName: "q",
- },
- },
- },
- variants: [
- {
- environment: { allRegionsAndLocales: true },
- },
- ],
- },
- {
- recordType: "defaultEngines",
- specificDefaults: [],
- },
- {
- recordType: "engineOrders",
- orders: [],
- },
-];
-
add_setup(async function () {
SearchTestUtils.useMockIdleService();
await AddonTestUtils.promiseStartupManager();
// This test purposely attempts to load a missing engine.
- consoleAllowList.push(
- "Could not load engine engine-missing@search.mozilla.org"
- );
+ consoleAllowList.push("Could not load engine");
});
add_task(async function test_startup_with_missing() {
- await SearchTestUtils.useTestEngines(
- "data",
- null,
- SearchUtils.newSearchConfigEnabled ? CONFIG_V2 : BAD_CONFIG
- );
+ await SearchTestUtils.useTestEngines("data", null, BAD_CONFIG);
const result = await Services.search.init();
Assert.ok(
@@ -135,7 +88,7 @@ add_task(async function test_update_with_missing() {
await RemoteSettings(SearchUtils.SETTINGS_KEY).emit("sync", {
data: {
- current: SearchUtils.newSearchConfigEnabled ? CONFIG_V2 : GOOD_CONFIG,
+ current: GOOD_CONFIG,
},
});
@@ -156,7 +109,7 @@ add_task(async function test_update_with_missing() {
await RemoteSettings(SearchUtils.SETTINGS_KEY).emit("sync", {
data: {
- current: SearchUtils.newSearchConfigEnabled ? CONFIG_V2 : BAD_CONFIG,
+ current: BAD_CONFIG,
},
});
diff --git a/toolkit/components/search/tests/xpcshell/test_webextensions_startup.js b/toolkit/components/search/tests/xpcshell/test_webextensions_startup.js
new file mode 100644
index 0000000000..0f106a2495
--- /dev/null
+++ b/toolkit/components/search/tests/xpcshell/test_webextensions_startup.js
@@ -0,0 +1,111 @@
+/* Any copyright is dedicated to the Public Domain.
+ http://creativecommons.org/publicdomain/zero/1.0/ */
+
+/**
+ * Tests to ensure that WebExtensions correctly load on startup without errors.
+ */
+
+"use strict";
+
+const lazy = {};
+
+ChromeUtils.defineESModuleGetters(lazy, {
+ ExtensionTestUtils:
+ "resource://testing-common/ExtensionXPCShellUtils.sys.mjs",
+});
+
+const { promiseShutdownManager, promiseStartupManager } = AddonTestUtils;
+
+let extension;
+
+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_startup_with_new_addon() {
+ // Although rare, handling loading an add-on on startup should work.
+ // Additionally, this sub-test allows us to pre-fill the search settings
+ // for the subsequent tests.
+
+ // 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: "startup",
+ search_url: "https://example.com/",
+ }),
+ };
+
+ extension = lazy.ExtensionTestUtils.loadExtension(extensionInfo);
+ await extension.startup();
+
+ let settingsWritten = promiseAfterSettings();
+ await Services.search.init();
+
+ await AddonTestUtils.waitForSearchProviderStartup(extension);
+ await settingsWritten;
+
+ let engine = await Services.search.getEngineByName("startup");
+ Assert.ok(engine, "Should have loaded the engine");
+ let submission = engine.getSubmission("foo");
+ Assert.equal(
+ submission.uri.spec,
+ "https://example.com/?q=foo",
+ "Should have the expected search url."
+ );
+});
+
+add_task(async function test_startup_with_existing_addon_from_settings() {
+ Services.search.wrappedJSObject.reset();
+
+ let settingsWritten = promiseAfterSettings();
+ await Services.search.init();
+ await settingsWritten;
+
+ let engine = await Services.search.getEngineByName("startup");
+ Assert.ok(engine, "Should have loaded the engine");
+ let submission = engine.getSubmission("foo");
+ Assert.equal(
+ submission.uri.spec,
+ "https://example.com/?q=foo",
+ "Should have the expected search url."
+ );
+});
+
+add_task(
+ async function test_startup_with_existing_addon_with_startup_notification() {
+ // Checks that we correctly load the add-on on startup when we are notified
+ // about it from the add-on manager before search has initialised. Also
+ // ensures that we don't raise an error when loading it from settings
+ // when the add-on is already there. The console check is handled by
+ // TestUtils.listenForConsoleMessages() in head_search.js.
+
+ Services.search.wrappedJSObject.reset();
+
+ await Services.search.addEnginesFromExtension(extension.extension);
+
+ let settingsWritten = promiseAfterSettings();
+ await Services.search.init();
+ await settingsWritten;
+
+ let engine = await Services.search.getEngineByName("startup");
+ Assert.ok(engine, "Should have loaded the engine");
+ let submission = engine.getSubmission("foo");
+ Assert.equal(
+ submission.uri.spec,
+ "https://example.com/?q=foo",
+ "Should have the expected search url."
+ );
+
+ await extension.unload();
+ }
+);
diff --git a/toolkit/components/search/tests/xpcshell/test_webextensions_startup_duplicate.js b/toolkit/components/search/tests/xpcshell/test_webextensions_startup_duplicate.js
index eb7e67e66e..cb7394d996 100644
--- a/toolkit/components/search/tests/xpcshell/test_webextensions_startup_duplicate.js
+++ b/toolkit/components/search/tests/xpcshell/test_webextensions_startup_duplicate.js
@@ -25,11 +25,7 @@ add_setup(async function () {
add_task(async function test_install_duplicate_engine_startup() {
let name = "Plain";
- let id = "plain@tests.mozilla.org";
- consoleAllowList.push(
- `#createAndAddAddonEngine failed for ${id}`,
- `An engine called ${name} already exists`
- );
+ consoleAllowList.push("#createAndAddAddonEngine failed for");
// Do not use SearchTestUtils.installSearchExtension, as we need to manually
// start the search service after installing the extension.
let extensionInfo = {
diff --git a/toolkit/components/search/tests/xpcshell/xpcshell.toml b/toolkit/components/search/tests/xpcshell/xpcshell.toml
index 899ac2d711..c21b98dffc 100644
--- a/toolkit/components/search/tests/xpcshell/xpcshell.toml
+++ b/toolkit/components/search/tests/xpcshell/xpcshell.toml
@@ -180,6 +180,7 @@ tags = "remotesettings searchmain"
["test_migrateWebExtensionEngine.js"]
["test_missing_engine.js"]
+prefs = ["browser.search.newSearchConfig.enabled=false"]
["test_nodb_pluschanges.js"]
@@ -323,6 +324,8 @@ support-files = ["data/search-migration.json"]
["test_webextensions_startup_remove.js"]
+["test_webextensions_startup.js"]
+
["test_webextensions_upgrade.js"]
["test_webextensions_valid.js"]