blob: 459bb75802a6fd55ce4f257b980251cb7768e0b1 [file] [log] [blame]
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "components/search_engines/reconciling_template_url_data_holder.h"
#include "base/feature_list.h"
#include "base/metrics/histogram_functions.h"
#include "base/strings/utf_string_conversions.h"
#include "components/search_engines/search_engines_switches.h"
#include "components/search_engines/template_url_data_util.h"
#include "components/search_engines/template_url_prepopulate_data.h"
#include "components/search_engines/template_url_prepopulate_data_resolver.h"
#include "third_party/search_engines_data/resources/definitions/prepopulated_engines.h"
ReconcilingTemplateURLDataHolder::ReconcilingTemplateURLDataHolder(
TemplateURLPrepopulateData::Resolver& prepopulate_data_resolver)
: prepopulate_data_resolver_(prepopulate_data_resolver) {}
ReconcilingTemplateURLDataHolder::~ReconcilingTemplateURLDataHolder() = default;
std::pair<std::u16string, bool>
ReconcilingTemplateURLDataHolder::GetOrComputeKeyword() const {
std::u16string keyword = search_engine_->keyword();
if (search_engine_->regulatory_origin == RegulatoryExtensionType::kDefault) {
return {std::move(keyword), false};
}
// Old Play API 'seznam.cz' and 'seznam.sk' have been consolidated to
// 'seznam'.
if (keyword.starts_with(u"seznam.")) {
return {u"seznam", true};
}
// Old Play API 'yahoo.com' entries are reconciled with country-specific
// definitions.
if (keyword != u"yahoo.com") {
return {std::move(keyword), false};
}
// The domain name prefix specifies the regional version of Yahoo's search
// engine requests. Until 08.2024 Android EEA Yahoo keywords all pointed
// to Yahoo US. See go/chrome:template-url-reconciliation for more
// information.
// Extract the Country Code from the Yahoo domain name and use it to
// construct a keyword that we may find in PrepopulatedEngines.
GURL yahoo_search_url(search_engine_->url());
std::string_view yahoo_search_host = yahoo_search_url.host();
std::string_view country_code =
yahoo_search_host.substr(0, yahoo_search_host.find('.'));
keyword = base::UTF8ToUTF16(country_code) + u".yahoo.com";
return {std::move(keyword), true};
}
std::unique_ptr<TemplateURLData>
ReconcilingTemplateURLDataHolder::FindMatchingBuiltInDefinitionsByKeyword(
const std::u16string& keyword) const {
std::vector<std::unique_ptr<TemplateURLData>> prepopulated_urls =
prepopulate_data_resolver_->GetPrepopulatedEngines();
auto engine_iter =
std::ranges::find(prepopulated_urls, keyword, &TemplateURLData::keyword);
std::unique_ptr<TemplateURLData> result;
if (engine_iter != prepopulated_urls.end()) {
result = std::move(*engine_iter);
} else {
// Search the entire search engine database to find matching entry.
auto all_engines = TemplateURLPrepopulateData::GetAllPrepopulatedEngines();
for (const auto* engine : all_engines) {
if (engine->keyword == keyword) {
result = TemplateURLDataFromPrepopulatedEngine(*engine);
break;
}
}
}
return result;
}
std::unique_ptr<TemplateURLData>
ReconcilingTemplateURLDataHolder::FindMatchingBuiltInDefinitionsById(
int prepopulate_id) const {
std::vector<std::unique_ptr<TemplateURLData>> prepopulated_urls =
prepopulate_data_resolver_->GetPrepopulatedEngines();
auto engine_iter = std::ranges::find(prepopulated_urls, prepopulate_id,
&TemplateURLData::prepopulate_id);
std::unique_ptr<TemplateURLData> result;
if (engine_iter != prepopulated_urls.end()) {
result = std::move(*engine_iter);
} else {
// Search the entire search engine database to find matching entry.
auto all_engines = TemplateURLPrepopulateData::GetAllPrepopulatedEngines();
for (const auto* engine : all_engines) {
if (engine->id == prepopulate_id) {
result = TemplateURLDataFromPrepopulatedEngine(*engine);
break;
}
}
}
return result;
}
void ReconcilingTemplateURLDataHolder::SetAndReconcile(
std::unique_ptr<TemplateURLData> data) {
enum class ReconciliationType {
kNone,
kByID,
kByKeyword,
kByDomainBasedKeyword,
kMaxValue = kByDomainBasedKeyword
};
search_engine_ = std::move(data);
if (!search_engine_) {
return;
}
// Evaluate whether items should be reconciled.
// Permit merging regulatory entries if feature is enabled.
bool reconcile_by_keyword =
search_engine_->regulatory_origin != RegulatoryExtensionType::kDefault;
// Permit merging by Prepopulated ID (except regulatory entries).
bool reconcile_by_id =
search_engine_->prepopulate_id &&
(search_engine_->regulatory_origin == RegulatoryExtensionType::kDefault);
// Don't call GetPrepopulatedEngines() if we don't have anything to reconcile.
if (!(reconcile_by_id || reconcile_by_keyword)) {
base::UmaHistogramEnumeration("Omnibox.TemplateUrl.Reconciliation.Type",
ReconciliationType::kNone);
return;
}
std::unique_ptr<TemplateURLData> engine;
if (reconcile_by_keyword) {
auto [keyword, is_by_domain_based_keyword] = GetOrComputeKeyword();
engine = FindMatchingBuiltInDefinitionsByKeyword(keyword);
base::UmaHistogramBoolean(
is_by_domain_based_keyword
? "Omnibox.TemplateUrl.Reconciliation.ByDomainBasedKeyword.Result"
: "Omnibox.TemplateUrl.Reconciliation.ByKeyword.Result",
!!engine);
base::UmaHistogramEnumeration(
"Omnibox.TemplateUrl.Reconciliation.Type",
is_by_domain_based_keyword ? ReconciliationType::kByDomainBasedKeyword
: ReconciliationType::kByKeyword);
} else if (reconcile_by_id) {
engine = FindMatchingBuiltInDefinitionsById(search_engine_->prepopulate_id);
base::UmaHistogramBoolean("Omnibox.TemplateUrl.Reconciliation.ByID.Result",
!!engine);
base::UmaHistogramEnumeration("Omnibox.TemplateUrl.Reconciliation.Type",
ReconciliationType::kByID);
}
if (!engine) {
return;
}
if (!search_engine_->safe_for_autoreplace) {
engine->safe_for_autoreplace = false;
engine->SetKeyword(search_engine_->keyword());
engine->SetShortName(search_engine_->short_name());
}
engine->id = search_engine_->id;
engine->sync_guid = search_engine_->sync_guid;
engine->date_created = search_engine_->date_created;
engine->last_modified = search_engine_->last_modified;
engine->last_visited = search_engine_->last_visited;
engine->favicon_url = search_engine_->favicon_url;
engine->regulatory_origin = search_engine_->regulatory_origin;
search_engine_ = std::move(engine);
}