Bug 1963622 - Vendor application-services 40ae79e. r=markh

Differential Revision: https://phabricator.services.mozilla.com/D247337
This commit is contained in:
Mark Banner
2025-05-05 08:33:34 +00:00
committed by mbanner@mozilla.com
parent c8d9a4c362
commit de138fd731
14 changed files with 642 additions and 106 deletions

View File

@@ -70,9 +70,9 @@ git = "https://github.com/jfkthame/mapped_hyph.git"
rev = "eff105f6ad7ec9b79816cfc1985a28e5340ad14b"
replace-with = "vendored-sources"
[source."git+https://github.com/mozilla/application-services?rev=280db3a3a06a8f517151ff0b84b5ce67fcc7afd6"]
[source."git+https://github.com/mozilla/application-services?rev=40ae79e2825fa242a349e17fcfc84fb99fd92197"]
git = "https://github.com/mozilla/application-services"
rev = "280db3a3a06a8f517151ff0b84b5ce67fcc7afd6"
rev = "40ae79e2825fa242a349e17fcfc84fb99fd92197"
replace-with = "vendored-sources"
[source."git+https://github.com/mozilla/audioipc?rev=e6f44a2bd1e57d11dfc737632a9e849077632330"]

32
Cargo.lock generated
View File

@@ -1852,7 +1852,7 @@ dependencies = [
[[package]]
name = "error-support"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=280db3a3a06a8f517151ff0b84b5ce67fcc7afd6#280db3a3a06a8f517151ff0b84b5ce67fcc7afd6"
source = "git+https://github.com/mozilla/application-services?rev=40ae79e2825fa242a349e17fcfc84fb99fd92197#40ae79e2825fa242a349e17fcfc84fb99fd92197"
dependencies = [
"error-support-macros",
"lazy_static",
@@ -1864,7 +1864,7 @@ dependencies = [
[[package]]
name = "error-support-macros"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=280db3a3a06a8f517151ff0b84b5ce67fcc7afd6#280db3a3a06a8f517151ff0b84b5ce67fcc7afd6"
source = "git+https://github.com/mozilla/application-services?rev=40ae79e2825fa242a349e17fcfc84fb99fd92197#40ae79e2825fa242a349e17fcfc84fb99fd92197"
dependencies = [
"proc-macro2",
"quote",
@@ -1983,7 +1983,7 @@ dependencies = [
[[package]]
name = "firefox-versioning"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=280db3a3a06a8f517151ff0b84b5ce67fcc7afd6#280db3a3a06a8f517151ff0b84b5ce67fcc7afd6"
source = "git+https://github.com/mozilla/application-services?rev=40ae79e2825fa242a349e17fcfc84fb99fd92197#40ae79e2825fa242a349e17fcfc84fb99fd92197"
dependencies = [
"serde_json",
"thiserror 1.999.999",
@@ -3323,7 +3323,7 @@ dependencies = [
[[package]]
name = "interrupt-support"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=280db3a3a06a8f517151ff0b84b5ce67fcc7afd6#280db3a3a06a8f517151ff0b84b5ce67fcc7afd6"
source = "git+https://github.com/mozilla/application-services?rev=40ae79e2825fa242a349e17fcfc84fb99fd92197#40ae79e2825fa242a349e17fcfc84fb99fd92197"
dependencies = [
"lazy_static",
"parking_lot",
@@ -5044,7 +5044,7 @@ checksum = "d01a5bd0424d00070b0098dd17ebca6f961a959dead1dbcbbbc1d1cd8d3deeba"
[[package]]
name = "payload-support"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=280db3a3a06a8f517151ff0b84b5ce67fcc7afd6#280db3a3a06a8f517151ff0b84b5ce67fcc7afd6"
source = "git+https://github.com/mozilla/application-services?rev=40ae79e2825fa242a349e17fcfc84fb99fd92197#40ae79e2825fa242a349e17fcfc84fb99fd92197"
dependencies = [
"serde",
"serde_derive",
@@ -5547,7 +5547,7 @@ checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
[[package]]
name = "relevancy"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=280db3a3a06a8f517151ff0b84b5ce67fcc7afd6#280db3a3a06a8f517151ff0b84b5ce67fcc7afd6"
source = "git+https://github.com/mozilla/application-services?rev=40ae79e2825fa242a349e17fcfc84fb99fd92197#40ae79e2825fa242a349e17fcfc84fb99fd92197"
dependencies = [
"anyhow",
"base64 0.21.999",
@@ -5572,7 +5572,7 @@ dependencies = [
[[package]]
name = "remote_settings"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=280db3a3a06a8f517151ff0b84b5ce67fcc7afd6#280db3a3a06a8f517151ff0b84b5ce67fcc7afd6"
source = "git+https://github.com/mozilla/application-services?rev=40ae79e2825fa242a349e17fcfc84fb99fd92197#40ae79e2825fa242a349e17fcfc84fb99fd92197"
dependencies = [
"anyhow",
"camino",
@@ -5913,7 +5913,7 @@ dependencies = [
[[package]]
name = "search"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=280db3a3a06a8f517151ff0b84b5ce67fcc7afd6#280db3a3a06a8f517151ff0b84b5ce67fcc7afd6"
source = "git+https://github.com/mozilla/application-services?rev=40ae79e2825fa242a349e17fcfc84fb99fd92197#40ae79e2825fa242a349e17fcfc84fb99fd92197"
dependencies = [
"error-support",
"firefox-versioning",
@@ -6205,7 +6205,7 @@ dependencies = [
[[package]]
name = "sql-support"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=280db3a3a06a8f517151ff0b84b5ce67fcc7afd6#280db3a3a06a8f517151ff0b84b5ce67fcc7afd6"
source = "git+https://github.com/mozilla/application-services?rev=40ae79e2825fa242a349e17fcfc84fb99fd92197#40ae79e2825fa242a349e17fcfc84fb99fd92197"
dependencies = [
"interrupt-support",
"lazy_static",
@@ -6411,7 +6411,7 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
[[package]]
name = "suggest"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=280db3a3a06a8f517151ff0b84b5ce67fcc7afd6#280db3a3a06a8f517151ff0b84b5ce67fcc7afd6"
source = "git+https://github.com/mozilla/application-services?rev=40ae79e2825fa242a349e17fcfc84fb99fd92197#40ae79e2825fa242a349e17fcfc84fb99fd92197"
dependencies = [
"anyhow",
"chrono",
@@ -6463,7 +6463,7 @@ dependencies = [
[[package]]
name = "sync-guid"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=280db3a3a06a8f517151ff0b84b5ce67fcc7afd6#280db3a3a06a8f517151ff0b84b5ce67fcc7afd6"
source = "git+https://github.com/mozilla/application-services?rev=40ae79e2825fa242a349e17fcfc84fb99fd92197#40ae79e2825fa242a349e17fcfc84fb99fd92197"
dependencies = [
"base64 0.21.999",
"rand",
@@ -6474,7 +6474,7 @@ dependencies = [
[[package]]
name = "sync15"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=280db3a3a06a8f517151ff0b84b5ce67fcc7afd6#280db3a3a06a8f517151ff0b84b5ce67fcc7afd6"
source = "git+https://github.com/mozilla/application-services?rev=40ae79e2825fa242a349e17fcfc84fb99fd92197#40ae79e2825fa242a349e17fcfc84fb99fd92197"
dependencies = [
"anyhow",
"error-support",
@@ -6514,7 +6514,7 @@ dependencies = [
[[package]]
name = "tabs"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=280db3a3a06a8f517151ff0b84b5ce67fcc7afd6#280db3a3a06a8f517151ff0b84b5ce67fcc7afd6"
source = "git+https://github.com/mozilla/application-services?rev=40ae79e2825fa242a349e17fcfc84fb99fd92197#40ae79e2825fa242a349e17fcfc84fb99fd92197"
dependencies = [
"anyhow",
"error-support",
@@ -6858,7 +6858,7 @@ checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "types"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=280db3a3a06a8f517151ff0b84b5ce67fcc7afd6#280db3a3a06a8f517151ff0b84b5ce67fcc7afd6"
source = "git+https://github.com/mozilla/application-services?rev=40ae79e2825fa242a349e17fcfc84fb99fd92197#40ae79e2825fa242a349e17fcfc84fb99fd92197"
dependencies = [
"rusqlite 0.33.0",
"serde",
@@ -7240,7 +7240,7 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "viaduct"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=280db3a3a06a8f517151ff0b84b5ce67fcc7afd6#280db3a3a06a8f517151ff0b84b5ce67fcc7afd6"
source = "git+https://github.com/mozilla/application-services?rev=40ae79e2825fa242a349e17fcfc84fb99fd92197#40ae79e2825fa242a349e17fcfc84fb99fd92197"
dependencies = [
"ffi-support",
"log",
@@ -7410,7 +7410,7 @@ dependencies = [
[[package]]
name = "webext-storage"
version = "0.1.0"
source = "git+https://github.com/mozilla/application-services?rev=280db3a3a06a8f517151ff0b84b5ce67fcc7afd6#280db3a3a06a8f517151ff0b84b5ce67fcc7afd6"
source = "git+https://github.com/mozilla/application-services?rev=40ae79e2825fa242a349e17fcfc84fb99fd92197#40ae79e2825fa242a349e17fcfc84fb99fd92197"
dependencies = [
"anyhow",
"error-support",

View File

@@ -262,14 +262,14 @@ wr_malloc_size_of = { path = "gfx/wr/wr_malloc_size_of" }
objc = { git = "https://github.com/glandium/rust-objc", rev = "4de89f5aa9851ceca4d40e7ac1e2759410c04324" }
# application-services overrides to make updating them all simpler.
interrupt-support = { git = "https://github.com/mozilla/application-services", rev = "280db3a3a06a8f517151ff0b84b5ce67fcc7afd6" }
relevancy = { git = "https://github.com/mozilla/application-services", rev = "280db3a3a06a8f517151ff0b84b5ce67fcc7afd6" }
search = { git = "https://github.com/mozilla/application-services", rev = "280db3a3a06a8f517151ff0b84b5ce67fcc7afd6" }
sql-support = { git = "https://github.com/mozilla/application-services", rev = "280db3a3a06a8f517151ff0b84b5ce67fcc7afd6" }
suggest = { git = "https://github.com/mozilla/application-services", rev = "280db3a3a06a8f517151ff0b84b5ce67fcc7afd6" }
sync15 = { git = "https://github.com/mozilla/application-services", rev = "280db3a3a06a8f517151ff0b84b5ce67fcc7afd6" }
tabs = { git = "https://github.com/mozilla/application-services", rev = "280db3a3a06a8f517151ff0b84b5ce67fcc7afd6" }
viaduct = { git = "https://github.com/mozilla/application-services", rev = "280db3a3a06a8f517151ff0b84b5ce67fcc7afd6" }
webext-storage = { git = "https://github.com/mozilla/application-services", rev = "280db3a3a06a8f517151ff0b84b5ce67fcc7afd6" }
interrupt-support = { git = "https://github.com/mozilla/application-services", rev = "40ae79e2825fa242a349e17fcfc84fb99fd92197" }
relevancy = { git = "https://github.com/mozilla/application-services", rev = "40ae79e2825fa242a349e17fcfc84fb99fd92197" }
search = { git = "https://github.com/mozilla/application-services", rev = "40ae79e2825fa242a349e17fcfc84fb99fd92197" }
sql-support = { git = "https://github.com/mozilla/application-services", rev = "40ae79e2825fa242a349e17fcfc84fb99fd92197" }
suggest = { git = "https://github.com/mozilla/application-services", rev = "40ae79e2825fa242a349e17fcfc84fb99fd92197" }
sync15 = { git = "https://github.com/mozilla/application-services", rev = "40ae79e2825fa242a349e17fcfc84fb99fd92197" }
tabs = { git = "https://github.com/mozilla/application-services", rev = "40ae79e2825fa242a349e17fcfc84fb99fd92197" }
viaduct = { git = "https://github.com/mozilla/application-services", rev = "40ae79e2825fa242a349e17fcfc84fb99fd92197" }
webext-storage = { git = "https://github.com/mozilla/application-services", rev = "40ae79e2825fa242a349e17fcfc84fb99fd92197" }
allocator-api2 = { path = "third_party/rust/allocator-api2" }

File diff suppressed because one or more lines are too long

View File

@@ -1,5 +1,155 @@
{
"data": [
{
"id": "96ad4fd9-4bbb-454d-bbe5-24225a2cbe04",
"last_modified": 1745933974542,
"locales": [
"af",
"an",
"ar",
"ast",
"az",
"be",
"bg",
"bn",
"bn-BD",
"bn-IN",
"br",
"bs",
"ca",
"ca-valencia",
"cak",
"cs",
"cy",
"da",
"de",
"dsb",
"el",
"en-CA",
"en-GB",
"en-US",
"eo",
"es-AR",
"es-CL",
"es-ES",
"es-MX",
"et",
"eu",
"fa",
"ff",
"fi",
"fr",
"fur",
"fy-NL",
"ga-IE",
"gd",
"gl",
"gn",
"gu-IN",
"he",
"hi-IN",
"hr",
"hsb",
"hu",
"hy-AM",
"ia",
"id",
"is",
"it",
"ja",
"ja-JP-macos",
"ka",
"kab",
"kk",
"km",
"kn",
"ko",
"lij",
"lo",
"lt",
"ltg",
"lv",
"mk",
"mr",
"ms",
"my",
"nb-NO",
"ne-NP",
"nl",
"nn-NO",
"oc",
"pa-IN",
"pl",
"pt-BR",
"pt-PT",
"rm",
"ro",
"ru",
"sc",
"sco",
"si",
"sk",
"sl",
"son",
"sq",
"sr",
"sv-SE",
"szl",
"ta",
"te",
"th",
"tl",
"tr",
"trs",
"uk",
"ur",
"uz",
"vi",
"wo",
"zh-CN",
"zh-TW"
],
"recordType": "availableLocales",
"schema": 1745887776020
},
{
"base": {
"aliases": [
"perplexity"
],
"classification": "general",
"name": "Perplexity",
"partnerCode": "firefox",
"urls": {
"search": {
"base": "https://www.perplexity.ai/search",
"params": [
{
"name": "pc",
"value": "{partnerCode}"
}
],
"searchTermParamName": "q"
},
"suggestions": {
"base": "https://suggest.perplexity.ai/suggest",
"searchTermParamName": "q"
}
}
},
"id": "bb836721-7be9-4de6-ac18-520189a69076",
"identifier": "perplexity",
"last_modified": 1745933974539,
"recordType": "engine",
"schema": 1745887296200,
"variants": [
{
"environment": {
"experiment": "perplexity"
}
}
]
},
{
"base": {
"aliases": [
@@ -3647,63 +3797,6 @@
}
]
},
{
"base": {
"aliases": [
"amazon"
],
"classification": "unknown",
"name": "Amazon.co.jp",
"partnerCode": "mozillajapan-fx-22",
"urls": {
"search": {
"base": "https://www.amazon.co.jp/exec/obidos/external-search/",
"params": [
{
"name": "mode",
"value": "blended"
},
{
"name": "tag",
"value": "{partnerCode}"
},
{
"name": "sourceid",
"value": "Mozilla-search"
}
],
"searchTermParamName": "field-keywords"
}
}
},
"id": "9d089e46-dc94-4d4f-8f17-cc07b59aa9e4",
"identifier": "amazon-jp",
"last_modified": 1718719100309,
"recordType": "engine",
"schema": 1718637175117,
"variants": [
{
"environment": {
"regions": [
"jp"
]
},
"subVariants": [
{
"environment": {
"applications": [
"firefox-android",
"focus-android",
"firefox-ios",
"focus-ios"
]
},
"partnerCode": "moz-jp-mbl-22"
}
]
}
]
},
{
"base": {
"aliases": [
@@ -8106,5 +8199,5 @@
]
}
],
"timestamp": 1742996759044
"timestamp": 1745933974542
}

View File

@@ -30,7 +30,9 @@ pub enum Error {
#[error("JSON Error: {0}")]
JSONError(#[from] serde_json::Error),
#[error("Error writing downloaded attachment: {0}")]
FileError(#[from] std::io::Error),
AttachmentFileError(std::io::Error),
#[error("Error creating storage dir: {0}")]
CreateDirError(std::io::Error),
/// An error has occurred while sending a request.
#[error("Error sending request: {0}")]
RequestError(#[from] viaduct::Error),
@@ -87,7 +89,7 @@ impl GetErrorHandling for Error {
_ => ErrorHandling::convert(RemoteSettingsError::Other {
reason: self.to_string(),
})
.report_error("logins-unexpected"),
.report_error("remote-settings-unexpected"),
}
}
}

View File

@@ -234,8 +234,8 @@ impl RemoteSettings {
path: String,
) -> ApiResult<()> {
let resp = self.client.get_attachment(&attachment_id)?;
let mut file = File::create(path)?;
file.write_all(&resp)?;
let mut file = File::create(path).map_err(Error::AttachmentFileError)?;
file.write_all(&resp).map_err(Error::AttachmentFileError)?;
Ok(())
}
}

View File

@@ -10,6 +10,7 @@ use camino::Utf8PathBuf;
use rusqlite::{params, Connection, OpenFlags, OptionalExtension, Transaction};
use serde_json;
use sha2::{Digest, Sha256};
use std::io;
use sql_support::{open_database::open_database_with_flags, ConnExt};
@@ -65,8 +66,13 @@ impl Storage {
let Some(dir) = self.path.parent() else {
return Ok(());
};
if !std::fs::exists(dir)? {
std::fs::create_dir(dir)?;
if !std::fs::exists(dir).map_err(Error::CreateDirError)? {
match std::fs::create_dir(dir) {
Ok(()) => (),
// Another thread created the directory, just ignore the error.
Err(e) if e.kind() == io::ErrorKind::AlreadyExists => (),
Err(e) => return Err(Error::CreateDirError(e)),
}
}
Ok(())
}

View File

@@ -1 +1 @@
{"files":{"Cargo.toml":"ac0ac2103375f1c3906436b53627f88515da74864dd3f86ebb2a18952ba72b30","README.md":"d59a6ad6232a86a7bd3632ca62c44ba8bd466615c5d47ce0d836b270bac5562c","android/build.gradle":"e3b617d653aa0221f2229bb16c2fd635003fe82d0274c4b9a6f2d8154851985a","android/proguard-rules.pro":"1cf8c57e8f79c250b0af9c1a5a4edad71a5c348a79ab70243b6bae086c150ad2","android/src/main/AndroidManifest.xml":"0a05039a6124be0296764c2b0f41e863b5538d75e6164dd9ae945b59d983c318","src/configuration_overrides_types.rs":"220a5e12ee3deb309a1571c5820ec5132c959f56667c4c48f997bbe2be0c7eeb","src/configuration_types.rs":"baea920438a87499791b33177c28b690356da24be13223f9113f40e43cb787d4","src/environment_matching.rs":"5a1ade9a900942c62e8740597528a34df6fb3fdb72c801a647a3386acd42fcc8","src/error.rs":"d3c1eda7a8da15446a321139d4d29dd9ceee99e916519690d5eb2d45ed628598","src/filter.rs":"2872eb2c965bdffdebf89936b3e7c80702c8d43e946da81ee093639ba8021f3b","src/lib.rs":"9c83780a74048fbbc7bbba5706067b9dc5db2ae25a0cc751687d2738903723b4","src/selector.rs":"9cdab3d61344cdb7715e51a46ea51e80dc668f22623a01be761450a1ac24082f","src/sort_helpers.rs":"12d41c34fc2ca5387edc248189335fb11702618b7253f8b486f0c84576084faa","src/types.rs":"2dc1339a5a49bc32dc9252d2fe1c179eb7b3d55f091d6ed2537262573e6d80db","uniffi.toml":"96f1cd569483ff59e3c73852f085a03889fa24a2ce20ff7a3003799a9f48a51e"},"package":null}
{"files":{"Cargo.toml":"ac0ac2103375f1c3906436b53627f88515da74864dd3f86ebb2a18952ba72b30","README.md":"d59a6ad6232a86a7bd3632ca62c44ba8bd466615c5d47ce0d836b270bac5562c","android/build.gradle":"e3b617d653aa0221f2229bb16c2fd635003fe82d0274c4b9a6f2d8154851985a","android/proguard-rules.pro":"1cf8c57e8f79c250b0af9c1a5a4edad71a5c348a79ab70243b6bae086c150ad2","android/src/main/AndroidManifest.xml":"0a05039a6124be0296764c2b0f41e863b5538d75e6164dd9ae945b59d983c318","src/configuration_overrides_types.rs":"220a5e12ee3deb309a1571c5820ec5132c959f56667c4c48f997bbe2be0c7eeb","src/configuration_types.rs":"a495199fc19cf9ce1aefe41058a38a0ffad4eb6f719fac11c11dcc3cfe4f234a","src/environment_matching.rs":"5a1ade9a900942c62e8740597528a34df6fb3fdb72c801a647a3386acd42fcc8","src/error.rs":"d3c1eda7a8da15446a321139d4d29dd9ceee99e916519690d5eb2d45ed628598","src/filter.rs":"88a39e594397708db888726cac00ad1e5b4a892c5a121c96cc11d20f41851b45","src/lib.rs":"9c83780a74048fbbc7bbba5706067b9dc5db2ae25a0cc751687d2738903723b4","src/selector.rs":"e065e05aec54e01fd106d453ece2cfee72793c8a47569cc32ac016aef3ac265b","src/sort_helpers.rs":"12d41c34fc2ca5387edc248189335fb11702618b7253f8b486f0c84576084faa","src/types.rs":"8721ccf9443b28435ba211d5705f4a6c82eb0354ba1d100045438800c7e2bf9a","uniffi.toml":"96f1cd569483ff59e3c73852f085a03889fa24a2ce20ff7a3003799a9f48a51e"},"package":null}

View File

@@ -37,7 +37,7 @@ impl JSONEngineMethod {
#[serde(rename_all = "camelCase")]
pub(crate) struct JSONEngineUrl {
/// The PrePath and FilePath of the URL. May include variables for engines
/// which have a variable FilePath, e.g. `{searchTerm}` for when a search
/// which have a variable FilePath, e.g. `{searchTerms}` for when a search
/// term is within the path of the url.
pub base: Option<String>,
@@ -49,7 +49,7 @@ pub(crate) struct JSONEngineUrl {
pub params: Option<Vec<SearchUrlParam>>,
/// The name of the query parameter for the search term. Automatically
/// appended to the end of the query. This may be skipped if `{searchTerm}`
/// appended to the end of the query. This may be skipped if `{searchTerms}`
/// is included in the base.
pub search_term_param_name: Option<String>,
}
@@ -277,6 +277,14 @@ pub(crate) struct JSONEngineOrdersRecord {
pub orders: Vec<JSONEngineOrder>,
}
/// Represents the available locales record.
#[derive(Debug, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub(crate) struct JSONAvailableLocalesRecord {
/// The available locales in the search config v2.
pub locales: Vec<String>,
}
/// Represents an individual record in the raw search configuration.
#[derive(Debug, Deserialize, Clone)]
#[serde(tag = "recordType", rename_all = "camelCase")]
@@ -284,6 +292,7 @@ pub(crate) enum JSONSearchConfigurationRecords {
DefaultEngines(JSONDefaultEnginesRecord),
Engine(Box<JSONEngineRecord>),
EngineOrders(JSONEngineOrdersRecord),
AvailableLocales(JSONAvailableLocalesRecord),
// Include some flexibilty if we choose to add new record types in future.
// Current versions of the application receiving the configuration will
// ignore the new record types.

View File

@@ -11,8 +11,9 @@ use crate::{
JSONEngineUrls, JSONEngineVariant, JSONSearchConfigurationRecords, RefinedSearchConfig,
SearchEngineDefinition, SearchEngineUrl, SearchEngineUrls, SearchUserEnvironment,
};
use crate::{sort_helpers, JSONEngineOrdersRecord};
use crate::{sort_helpers, JSONAvailableLocalesRecord, JSONEngineOrdersRecord};
use remote_settings::RemoteSettingsRecord;
use std::collections::HashSet;
impl From<JSONEngineUrl> for SearchEngineUrl {
fn from(url: JSONEngineUrl) -> Self {
@@ -143,7 +144,7 @@ pub(crate) struct FilterRecordsResult {
pub(crate) trait Filter {
fn filter_records(
&self,
user_environment: &SearchUserEnvironment,
user_environment: &mut SearchUserEnvironment,
overrides: Option<Vec<JSONOverridesRecord>>,
) -> Result<FilterRecordsResult, Error>;
}
@@ -158,12 +159,48 @@ fn apply_overrides(engines: &mut [SearchEngineDefinition], overrides: &[JSONOver
}
}
fn negotiate_languages(user_environment: &mut SearchUserEnvironment, available_locales: &[String]) {
let user_locale = user_environment.locale.to_lowercase();
let available_locales_set: HashSet<String> = available_locales
.iter()
.map(|locale| locale.to_lowercase())
.collect();
if available_locales_set.contains(&user_locale) {
return;
}
if user_locale.starts_with("en-") {
user_environment.locale = "en-us".to_string();
return;
}
if let Some(index) = user_locale.find('-') {
let base_locale = &user_locale[..index];
if available_locales_set.contains(base_locale) {
user_environment.locale = base_locale.to_string();
}
}
}
impl Filter for Vec<RemoteSettingsRecord> {
fn filter_records(
&self,
user_environment: &SearchUserEnvironment,
user_environment: &mut SearchUserEnvironment,
overrides: Option<Vec<JSONOverridesRecord>>,
) -> Result<FilterRecordsResult, Error> {
let mut available_locales = Vec::new();
for record in self {
if let Some(val) = record.fields.get("recordType") {
if *val == "availableLocales" {
let stringified = serde_json::to_string(&record.fields)?;
let locales_record: Option<JSONAvailableLocalesRecord> =
serde_json::from_str(&stringified)?;
available_locales = locales_record.unwrap().locales;
}
}
}
negotiate_languages(user_environment, &available_locales);
let mut engines = Vec::new();
let mut default_engines_record = None;
let mut engine_orders_record = None;
@@ -188,6 +225,9 @@ impl Filter for Vec<RemoteSettingsRecord> {
Some(val) if *val == "engineOrders" => {
engine_orders_record = serde_json::from_str(&stringified)?;
}
Some(val) if *val == "availableLocales" => {
// Handled above
}
// These cases are acceptable - we expect the potential for new
// record types/options so that we can be flexible.
Some(_val) => {}
@@ -210,9 +250,17 @@ impl Filter for Vec<RemoteSettingsRecord> {
impl Filter for Vec<JSONSearchConfigurationRecords> {
fn filter_records(
&self,
user_environment: &SearchUserEnvironment,
user_environment: &mut SearchUserEnvironment,
overrides: Option<Vec<JSONOverridesRecord>>,
) -> Result<FilterRecordsResult, Error> {
let mut available_locales = Vec::new();
for record in self {
if let JSONSearchConfigurationRecords::AvailableLocales(locales_record) = record {
available_locales = locales_record.locales.clone();
}
}
negotiate_languages(user_environment, &available_locales);
let mut engines = Vec::new();
let mut default_engines_record = None;
let mut engine_orders_record = None;
@@ -229,6 +277,9 @@ impl Filter for Vec<JSONSearchConfigurationRecords> {
JSONSearchConfigurationRecords::EngineOrders(engine_orders) => {
engine_orders_record = Some(engine_orders)
}
JSONSearchConfigurationRecords::AvailableLocales(_) => {
// Handled above
}
JSONSearchConfigurationRecords::Unknown => {
// Prevents panics if a new record type is added in future.
}
@@ -246,6 +297,7 @@ impl Filter for Vec<JSONSearchConfigurationRecords> {
})
}
}
pub(crate) fn filter_engine_configuration_impl(
user_environment: SearchUserEnvironment,
configuration: &impl Filter,
@@ -256,7 +308,7 @@ pub(crate) fn filter_engine_configuration_impl(
user_environment.region = user_environment.region.to_lowercase();
user_environment.version = user_environment.version.to_lowercase();
let filtered_result = configuration.filter_records(&user_environment, overrides);
let filtered_result = configuration.filter_records(&mut user_environment, overrides);
filtered_result.map(|result| {
let (default_engine_id, default_private_engine_id) = determine_default_engines(
@@ -1327,4 +1379,61 @@ mod tests {
"Should have returned the specific default for private mode when using a wildcard match"
);
}
#[test]
fn test_locale_matched_exactly() {
let mut user_env = SearchUserEnvironment {
locale: "en-CA".into(),
..Default::default()
};
negotiate_languages(&mut user_env, &["en-CA".to_string(), "fr".to_string()]);
assert_eq!(
user_env.locale, "en-CA",
"Should return user locale unchanged if in available locales"
);
}
#[test]
fn test_locale_fallback_to_base_locale() {
let mut user_env = SearchUserEnvironment {
locale: "de-AT".into(),
..Default::default()
};
negotiate_languages(&mut user_env, &["de".to_string()]);
assert_eq!(
user_env.locale, "de",
"Should fallback to base locale if base is in available locales"
);
}
static ENGLISH_LOCALES: &[&str] = &["en-AU", "en-IE", "en-RU", "en-ZA"];
#[test]
fn test_english_locales_fallbacks_to_en_us() {
for user_locale in ENGLISH_LOCALES {
let mut user_env = SearchUserEnvironment {
locale: user_locale.to_string(),
..Default::default()
};
negotiate_languages(&mut user_env, &["en-US".to_string()]);
assert_eq!(
user_env.locale, "en-us",
"Should remap {} to en-us when en-us is available",
user_locale
);
}
}
#[test]
fn test_locale_unmatched() {
let mut user_env = SearchUserEnvironment {
locale: "fr-CA".into(),
..Default::default()
};
negotiate_languages(&mut user_env, &["de".to_string(), "en-US".to_string()]);
assert_eq!(
user_env.locale, "fr-CA",
"Should leave locale unchanged if no match or english locale fallback is not found"
);
}
}

View File

@@ -912,6 +912,10 @@ mod tests {
{
"recordType": "defaultEngines",
"globalDefault": "test1"
},
{
"recordType": "availableLocales",
"locales": ["en-CA", "fr"]
}
]
})
@@ -1677,6 +1681,10 @@ mod tests {
},
],
},
{
"recordType": "availableLocales",
"locales": ["en-CA", "fr"]
}
]
})
.to_string(),
@@ -1829,6 +1837,11 @@ mod tests {
},
],
},
{
"recordType": "availableLocales",
"locales": ["en-CA", "en-GB", "fr"]
}
]
})
.to_string(),
@@ -2008,6 +2021,75 @@ mod tests {
.to_string()
}
fn response_body_locales() -> String {
json!({
"metadata": {
"id": "search-config-v2",
"last_modified": 1000,
"bucket": "main",
"signature": {
"x5u": "fake",
"signature": "fake",
},
},
"timestamp": 1000,
"changes": [
{
"recordType": "engine",
"identifier": "engine-de",
"base": {
"name": "German Engine",
"classification": "general",
"urls": {
"search": {
"base": "https://example.com",
"method": "GET",
}
}
},
"variants": [{
"environment": {
"locales": ["de"]
}
}],
"id": "c5dcd1da-7126-4abb-846b-ec85b0d4d0d7",
"schema": 1001,
"last_modified": 1000
},
{
"recordType": "engine",
"identifier": "engine-en-us",
"base": {
"name": "English US Engine",
"classification": "general",
"urls": {
"search": {
"base": "https://example.com",
"method": "GET"
}
}
},
"variants": [{
"environment": {
"locales": ["en-US"]
}
}],
"id": "c5dcd1da-7126-4abb-846b-ec85b0d4d0d8",
"schema": 1002,
"last_modified": 1000
},
{
"recordType": "availableLocales",
"locales": ["de", "en-US"],
"id": "c5dcd1da-7126-4abb-846b-ec85b0d4d0e0",
"schema": 1004,
"last_modified": 1000,
}
]
})
.to_string()
}
fn response_body_overrides() -> String {
json!({
"metadata": {
@@ -2389,6 +2471,89 @@ mod tests {
m.expect(1).assert();
}
#[test]
fn test_filter_with_remote_settings_negotiate_locales() {
let m = mock(
"GET",
"/v1/buckets/main/collections/search-config-v2/changeset?_expected=0",
)
.with_body(response_body_locales())
.with_status(200)
.with_header("content-type", "application/json")
.with_header("etag", "\"1000\"")
.create();
let selector = setup_remote_settings_test(DO_NOT_APPLY_OVERRIDES, RECORDS_PRESENT);
let de_engine = SearchEngineDefinition {
charset: "UTF-8".to_string(),
classification: SearchEngineClassification::General,
identifier: "engine-de".to_string(),
name: "German Engine".to_string(),
urls: SearchEngineUrls {
search: SearchEngineUrl {
base: "https://example.com".to_string(),
method: "GET".to_string(),
params: Vec::new(),
search_term_param_name: None,
},
..Default::default()
},
..Default::default()
};
let en_us_engine = SearchEngineDefinition {
charset: "UTF-8".to_string(),
classification: SearchEngineClassification::General,
identifier: "engine-en-us".to_string(),
name: "English US Engine".to_string(),
urls: SearchEngineUrls {
search: SearchEngineUrl {
base: "https://example.com".to_string(),
method: "GET".to_string(),
params: Vec::new(),
search_term_param_name: None,
},
..Default::default()
},
..Default::default()
};
let result_de = Arc::clone(&selector).filter_engine_configuration(SearchUserEnvironment {
locale: "de-AT".into(),
..Default::default()
});
assert!(
result_de.is_ok(),
"Should have filtered the configuration without error. {:?}",
result_de
);
assert_eq!(
result_de.unwrap(),
RefinedSearchConfig {
engines: vec![de_engine,],
app_default_engine_id: None,
app_private_default_engine_id: None,
},
"Should have selected the de engine when given de-AT which is not an available locale"
);
let result_en = Arc::clone(&selector).filter_engine_configuration(SearchUserEnvironment {
locale: "en-AU".to_string(),
..Default::default()
});
assert_eq!(
result_en.unwrap(),
RefinedSearchConfig {
engines: vec![en_us_engine,],
app_default_engine_id: None,
app_private_default_engine_id: None,
},
"Should have selected the en-us engine when given another english locale we don't support"
);
m.expect(1).assert();
}
#[test]
fn test_configuration_overrides_applied() {
let selector = Arc::new(SearchEngineSelector::new());
@@ -2546,4 +2711,156 @@ mod tests {
"Should have applied the overrides to the matching engine."
);
}
#[test]
fn test_filter_engine_configuration_negotiate_locales() {
let selector = Arc::new(SearchEngineSelector::new());
let config_overrides_result = Arc::clone(&selector).set_config_overrides(
json!({
"data": [
{
"identifier": "overrides-engine",
"partnerCode": "overrides-partner-code",
"clickUrl": "https://example.com/click-url",
"telemetrySuffix": "overrides-telemetry-suffix",
"urls": {
"search": {
"base": "https://example.com/search-overrides",
"method": "GET",
"params": []
}
}
}
]
})
.to_string(),
);
let config_result = Arc::clone(&selector).set_search_config(
json!({
"data": [
{
"recordType": "availableLocales",
"locales": ["de", "en-US"]
},
{
"recordType": "engine",
"identifier": "engine-de",
"base": {
"name": "German Engine",
"classification": "general",
"urls": {
"search": {
"base": "https://example.com",
"method": "GET",
}
}
},
"variants": [{
"environment": {
"locales": ["de"]
}
}],
},
{
"recordType": "engine",
"identifier": "engine-en-us",
"base": {
"name": "English US Engine",
"classification": "general",
"urls": {
"search": {
"base": "https://example.com",
"method": "GET"
}
}
},
"variants": [{
"environment": {
"locales": ["en-US"]
}
}],
},
]
})
.to_string(),
);
assert!(
config_result.is_ok(),
"Should have set the configuration successfully. {:?}",
config_result
);
assert!(
config_overrides_result.is_ok(),
"Should have set the configuration overrides successfully. {:?}",
config_overrides_result
);
let de_engine = SearchEngineDefinition {
charset: "UTF-8".to_string(),
classification: SearchEngineClassification::General,
identifier: "engine-de".to_string(),
name: "German Engine".to_string(),
urls: SearchEngineUrls {
search: SearchEngineUrl {
base: "https://example.com".to_string(),
method: "GET".to_string(),
params: Vec::new(),
search_term_param_name: None,
},
..Default::default()
},
..Default::default()
};
let en_us_engine = SearchEngineDefinition {
charset: "UTF-8".to_string(),
classification: SearchEngineClassification::General,
identifier: "engine-en-us".to_string(),
name: "English US Engine".to_string(),
urls: SearchEngineUrls {
search: SearchEngineUrl {
base: "https://example.com".to_string(),
method: "GET".to_string(),
params: Vec::new(),
search_term_param_name: None,
},
..Default::default()
},
..Default::default()
};
let result_de = Arc::clone(&selector).filter_engine_configuration(SearchUserEnvironment {
locale: "de-AT".into(),
..Default::default()
});
assert!(
result_de.is_ok(),
"Should have filtered the configuration without error. {:?}",
result_de
);
assert_eq!(
result_de.unwrap(),
RefinedSearchConfig {
engines: vec![de_engine,],
app_default_engine_id: None,
app_private_default_engine_id: None,
},
"Should have selected the de engine when given de-AT which is not an available locale"
);
let result_en = Arc::clone(&selector).filter_engine_configuration(SearchUserEnvironment {
locale: "en-AU".to_string(),
..Default::default()
});
assert_eq!(
result_en.unwrap(),
RefinedSearchConfig {
engines: vec![en_us_engine,],
app_default_engine_id: None,
app_private_default_engine_id: None,
},
"Should have selected the en-us engine when given another english locale we don't support"
);
}
}

View File

@@ -111,7 +111,7 @@ pub struct SearchUrlParam {
#[derive(Debug, uniffi::Record, PartialEq, Deserialize, Clone, Default)]
pub struct SearchEngineUrl {
/// The PrePath and FilePath of the URL. May include variables for engines
/// which have a variable FilePath, e.g. `{searchTerm}` for when a search
/// which have a variable FilePath, e.g. `{searchTerms}` for when a search
/// term is within the path of the url.
pub base: String,
@@ -123,7 +123,7 @@ pub struct SearchEngineUrl {
pub params: Vec<SearchUrlParam>,
/// The name of the query parameter for the search term. Automatically
/// appended to the end of the query. This may be skipped if `{searchTerm}`
/// appended to the end of the query. This may be skipped if `{searchTerms}`
/// is included in the base.
pub search_term_param_name: Option<String>,
}

View File

@@ -615,7 +615,7 @@ export class JsonEngineUrl {
}
/**
* The PrePath and FilePath of the URL. May include variables for engines
* which have a variable FilePath, e.g. `{searchTerm}` for when a search
* which have a variable FilePath, e.g. `{searchTerms}` for when a search
* term is within the path of the url.
* @type {?string}
*/
@@ -633,7 +633,7 @@ export class JsonEngineUrl {
this.params = params;
/**
* The name of the query parameter for the search term. Automatically
* appended to the end of the query. This may be skipped if `{searchTerm}`
* appended to the end of the query. This may be skipped if `{searchTerms}`
* is included in the base.
* @type {?string}
*/
@@ -1343,7 +1343,7 @@ export class SearchEngineUrl {
}
/**
* The PrePath and FilePath of the URL. May include variables for engines
* which have a variable FilePath, e.g. `{searchTerm}` for when a search
* which have a variable FilePath, e.g. `{searchTerms}` for when a search
* term is within the path of the url.
* @type {string}
*/
@@ -1361,7 +1361,7 @@ export class SearchEngineUrl {
this.params = params;
/**
* The name of the query parameter for the search term. Automatically
* appended to the end of the query. This may be skipped if `{searchTerm}`
* appended to the end of the query. This may be skipped if `{searchTerms}`
* is included in the base.
* @type {?string}
*/