blob: 322f686adee919d227472992826c826b042d8ca3 [file] [log] [blame]
// Copyright 2016 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/template_url_data_util.h"
#include <string>
#include <string_view>
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/utf_string_conversions.h"
#include "base/values.h"
#include "components/search_engines/default_search_manager.h"
#include "components/search_engines/prepopulated_engines.h"
#include "components/search_engines/template_url_data.h"
#include "components/search_engines/template_url_starter_pack_data.h"
#include "ui/base/l10n/l10n_util.h"
#include "url/gurl.h"
namespace {
// Converts the C-style string `str` to a base::StringPiece making sure to avoid
// dereferencing nullptrs.
base::StringPiece ToStringPiece(const char* str) {
return str ? base::StringPiece(str) : base::StringPiece();
}
std::u16string_view ToU16StringView(const char16_t* str) {
return str ? std::u16string_view(str) : std::u16string_view();
}
} // namespace
std::unique_ptr<TemplateURLData> TemplateURLDataFromDictionary(
const base::Value::Dict& dict) {
const std::string* search_url = dict.FindString(DefaultSearchManager::kURL);
const std::string* keyword = dict.FindString(DefaultSearchManager::kKeyword);
const std::string* short_name =
dict.FindString(DefaultSearchManager::kShortName);
// Check required TemplateURLData fields first.
if (!search_url || !keyword || !short_name) {
return nullptr;
}
auto result = std::make_unique<TemplateURLData>();
result->SetKeyword(base::UTF8ToUTF16(*keyword));
result->SetURL(*search_url);
const std::string* id = dict.FindString(DefaultSearchManager::kID);
if (id) {
base::StringToInt64(*id, &result->id);
}
const std::string* string_value = nullptr;
result->SetShortName(base::UTF8ToUTF16(*short_name));
result->prepopulate_id = dict.FindInt(DefaultSearchManager::kPrepopulateID)
.value_or(result->prepopulate_id);
result->starter_pack_id = dict.FindInt(DefaultSearchManager::kStarterPackId)
.value_or(result->starter_pack_id);
string_value = dict.FindString(DefaultSearchManager::kSyncGUID);
if (string_value) {
result->sync_guid = *string_value;
}
string_value = dict.FindString(DefaultSearchManager::kSuggestionsURL);
if (string_value) {
result->suggestions_url = *string_value;
}
string_value = dict.FindString(DefaultSearchManager::kImageURL);
if (string_value) {
result->image_url = *string_value;
}
string_value = dict.FindString(DefaultSearchManager::kImageTranslateURL);
if (string_value) {
result->image_translate_url = *string_value;
}
string_value = dict.FindString(DefaultSearchManager::kNewTabURL);
if (string_value) {
result->new_tab_url = *string_value;
}
string_value = dict.FindString(DefaultSearchManager::kContextualSearchURL);
if (string_value) {
result->contextual_search_url = *string_value;
}
string_value = dict.FindString(DefaultSearchManager::kFaviconURL);
if (string_value) {
result->favicon_url = GURL(*string_value);
}
string_value = dict.FindString(DefaultSearchManager::kOriginatingURL);
if (string_value) {
result->originating_url = GURL(*string_value);
}
string_value = dict.FindString(DefaultSearchManager::kLogoURL);
if (string_value) {
result->logo_url = GURL(*string_value);
}
string_value = dict.FindString(DefaultSearchManager::kDoodleURL);
if (string_value) {
result->doodle_url = GURL(*string_value);
}
const std::string* search_url_post_params =
dict.FindString(DefaultSearchManager::kSearchURLPostParams);
if (search_url_post_params) {
result->search_url_post_params = *search_url_post_params;
}
const std::string* suggestions_url_post_params =
dict.FindString(DefaultSearchManager::kSuggestionsURLPostParams);
if (suggestions_url_post_params) {
result->suggestions_url_post_params = *suggestions_url_post_params;
}
const std::string* image_url_post_params =
dict.FindString(DefaultSearchManager::kImageURLPostParams);
if (image_url_post_params) {
result->image_url_post_params = *image_url_post_params;
}
const std::string* side_search_param =
dict.FindString(DefaultSearchManager::kSideSearchParam);
if (side_search_param) {
result->side_search_param = *side_search_param;
}
const std::string* side_image_search_param =
dict.FindString(DefaultSearchManager::kSideImageSearchParam);
if (side_image_search_param) {
result->side_image_search_param = *side_image_search_param;
}
const std::string* image_translate_source_language_param_key =
dict.FindString(
DefaultSearchManager::kImageTranslateSourceLanguageParamKey);
if (image_translate_source_language_param_key) {
result->image_translate_source_language_param_key =
*image_translate_source_language_param_key;
}
const std::string* image_translate_target_language_param_key =
dict.FindString(
DefaultSearchManager::kImageTranslateTargetLanguageParamKey);
if (image_translate_target_language_param_key) {
result->image_translate_target_language_param_key =
*image_translate_target_language_param_key;
}
const std::string* image_search_branding_label =
dict.FindString(DefaultSearchManager::kImageSearchBrandingLabel);
if (image_search_branding_label) {
result->image_search_branding_label =
base::UTF8ToUTF16(*image_search_branding_label);
}
const base::Value::List* additional_params_list =
dict.FindList(DefaultSearchManager::kSearchIntentParams);
if (additional_params_list) {
for (const auto& additional_param_value : *additional_params_list) {
const auto* additional_param = additional_param_value.GetIfString();
DCHECK(additional_param && !additional_param->empty());
if (additional_param && !additional_param->empty()) {
result->search_intent_params.push_back(*additional_param);
}
}
}
std::optional<bool> safe_for_autoreplace =
dict.FindBool(DefaultSearchManager::kSafeForAutoReplace);
if (safe_for_autoreplace) {
result->safe_for_autoreplace = *safe_for_autoreplace;
}
std::string date_created_str;
std::string last_modified_str;
std::string last_visited_str;
string_value = dict.FindString(DefaultSearchManager::kDateCreated);
if (string_value) {
date_created_str = *string_value;
}
string_value = dict.FindString(DefaultSearchManager::kLastModified);
if (string_value) {
last_modified_str = *string_value;
}
string_value = dict.FindString(DefaultSearchManager::kLastVisited);
if (string_value) {
last_visited_str = *string_value;
}
int64_t date_created = 0;
if (base::StringToInt64(date_created_str, &date_created))
result->date_created = base::Time::FromInternalValue(date_created);
int64_t last_modified = 0;
if (base::StringToInt64(last_modified_str, &last_modified))
result->last_modified = base::Time::FromInternalValue(last_modified);
int64_t last_visited = 0;
if (base::StringToInt64(last_visited_str, &last_visited))
result->last_visited = base::Time::FromInternalValue(last_visited);
result->usage_count = dict.FindInt(DefaultSearchManager::kUsageCount)
.value_or(result->usage_count);
const base::Value::List* alternate_urls =
dict.FindList(DefaultSearchManager::kAlternateURLs);
if (alternate_urls) {
for (const auto& it : *alternate_urls) {
if (it.is_string())
result->alternate_urls.push_back(it.GetString());
}
}
const base::Value::List* encodings =
dict.FindList(DefaultSearchManager::kInputEncodings);
if (encodings) {
for (const auto& it : *encodings) {
std::string encoding;
if (it.is_string())
result->input_encodings.push_back(it.GetString());
}
}
result->created_by_policy = static_cast<TemplateURLData::CreatedByPolicy>(
dict.FindInt(DefaultSearchManager::kCreatedByPolicy)
.value_or(static_cast<int>(result->created_by_policy)));
result->created_from_play_api =
dict.FindBool(DefaultSearchManager::kCreatedFromPlayAPI)
.value_or(result->created_from_play_api);
result->featured_by_policy =
dict.FindBool(DefaultSearchManager::kFeaturedByPolicy)
.value_or(result->featured_by_policy);
result->preconnect_to_search_url =
dict.FindBool(DefaultSearchManager::kPreconnectToSearchUrl)
.value_or(result->preconnect_to_search_url);
result->prefetch_likely_navigations =
dict.FindBool(DefaultSearchManager::kPrefetchLikelyNavigations)
.value_or(result->prefetch_likely_navigations);
result->is_active = static_cast<TemplateURLData::ActiveStatus>(
dict.FindInt(DefaultSearchManager::kIsActive)
.value_or(static_cast<int>(result->is_active)));
result->enforced_by_policy =
dict.FindBool(DefaultSearchManager::kEnforcedByPolicy)
.value_or(result->enforced_by_policy);
return result;
}
base::Value::Dict TemplateURLDataToDictionary(const TemplateURLData& data) {
base::Value::Dict url_dict;
url_dict.Set(DefaultSearchManager::kID, base::NumberToString(data.id));
url_dict.Set(DefaultSearchManager::kShortName, data.short_name());
url_dict.Set(DefaultSearchManager::kKeyword, data.keyword());
url_dict.Set(DefaultSearchManager::kPrepopulateID, data.prepopulate_id);
url_dict.Set(DefaultSearchManager::kStarterPackId, data.starter_pack_id);
url_dict.Set(DefaultSearchManager::kSyncGUID, data.sync_guid);
url_dict.Set(DefaultSearchManager::kURL, data.url());
url_dict.Set(DefaultSearchManager::kSuggestionsURL, data.suggestions_url);
url_dict.Set(DefaultSearchManager::kImageURL, data.image_url);
url_dict.Set(DefaultSearchManager::kImageTranslateURL,
data.image_translate_url);
url_dict.Set(DefaultSearchManager::kNewTabURL, data.new_tab_url);
url_dict.Set(DefaultSearchManager::kContextualSearchURL,
data.contextual_search_url);
url_dict.Set(DefaultSearchManager::kFaviconURL, data.favicon_url.spec());
url_dict.Set(DefaultSearchManager::kOriginatingURL,
data.originating_url.spec());
url_dict.Set(DefaultSearchManager::kLogoURL, data.logo_url.spec());
url_dict.Set(DefaultSearchManager::kDoodleURL, data.doodle_url.spec());
url_dict.Set(DefaultSearchManager::kSearchURLPostParams,
data.search_url_post_params);
url_dict.Set(DefaultSearchManager::kSuggestionsURLPostParams,
data.suggestions_url_post_params);
url_dict.Set(DefaultSearchManager::kImageURLPostParams,
data.image_url_post_params);
url_dict.Set(DefaultSearchManager::kSideSearchParam, data.side_search_param);
url_dict.Set(DefaultSearchManager::kSideImageSearchParam,
data.side_image_search_param);
url_dict.Set(DefaultSearchManager::kImageTranslateSourceLanguageParamKey,
data.image_translate_source_language_param_key);
url_dict.Set(DefaultSearchManager::kImageTranslateTargetLanguageParamKey,
data.image_translate_target_language_param_key);
url_dict.Set(DefaultSearchManager::kImageSearchBrandingLabel,
data.image_search_branding_label);
base::Value::List additional_params_list;
for (const auto& additional_param : data.search_intent_params) {
additional_params_list.Append(additional_param);
}
url_dict.Set(DefaultSearchManager::kSearchIntentParams,
std::move(additional_params_list));
url_dict.Set(DefaultSearchManager::kSafeForAutoReplace,
data.safe_for_autoreplace);
url_dict.Set(DefaultSearchManager::kDateCreated,
base::NumberToString(data.date_created.ToInternalValue()));
url_dict.Set(DefaultSearchManager::kLastModified,
base::NumberToString(data.last_modified.ToInternalValue()));
url_dict.Set(DefaultSearchManager::kLastVisited,
base::NumberToString(data.last_visited.ToInternalValue()));
url_dict.Set(DefaultSearchManager::kUsageCount, data.usage_count);
base::Value::List alternate_urls;
for (const auto& alternate_url : data.alternate_urls)
alternate_urls.Append(alternate_url);
url_dict.Set(DefaultSearchManager::kAlternateURLs, std::move(alternate_urls));
base::Value::List encodings;
for (const auto& input_encoding : data.input_encodings)
encodings.Append(input_encoding);
url_dict.Set(DefaultSearchManager::kInputEncodings, std::move(encodings));
url_dict.Set(DefaultSearchManager::kCreatedByPolicy,
static_cast<int>(data.created_by_policy));
url_dict.Set(DefaultSearchManager::kCreatedFromPlayAPI,
data.created_from_play_api);
url_dict.Set(DefaultSearchManager::kFeaturedByPolicy,
data.featured_by_policy);
url_dict.Set(DefaultSearchManager::kPreconnectToSearchUrl,
data.preconnect_to_search_url);
url_dict.Set(DefaultSearchManager::kPrefetchLikelyNavigations,
data.prefetch_likely_navigations);
url_dict.Set(DefaultSearchManager::kIsActive,
static_cast<int>(data.is_active));
url_dict.Set(DefaultSearchManager::kEnforcedByPolicy,
data.enforced_by_policy);
return url_dict;
}
std::unique_ptr<TemplateURLData> TemplateURLDataFromPrepopulatedEngine(
const TemplateURLPrepopulateData::PrepopulatedEngine& engine) {
std::vector<std::string> search_intent_params;
if (engine.search_intent_params) {
for (size_t i = 0; i < engine.search_intent_params_size; ++i) {
search_intent_params.emplace_back(engine.search_intent_params[i]);
}
}
base::Value::List alternate_urls;
if (engine.alternate_urls) {
for (size_t i = 0; i < engine.alternate_urls_size; ++i)
alternate_urls.Append(std::string(engine.alternate_urls[i]));
}
std::u16string image_search_branding_label =
engine.image_search_branding_label ? engine.image_search_branding_label
: std::u16string();
return std::make_unique<TemplateURLData>(
ToU16StringView(engine.name), ToU16StringView(engine.keyword),
ToStringPiece(engine.search_url), ToStringPiece(engine.suggest_url),
ToStringPiece(engine.image_url),
ToStringPiece(engine.image_translate_url),
ToStringPiece(engine.new_tab_url),
ToStringPiece(engine.contextual_search_url),
ToStringPiece(engine.logo_url), ToStringPiece(engine.doodle_url),
ToStringPiece(engine.search_url_post_params),
ToStringPiece(engine.suggest_url_post_params),
ToStringPiece(engine.image_url_post_params),
ToStringPiece(engine.side_search_param),
ToStringPiece(engine.side_image_search_param),
ToStringPiece(engine.image_translate_source_language_param_key),
ToStringPiece(engine.image_translate_target_language_param_key),
std::move(search_intent_params), ToStringPiece(engine.favicon_url),
ToStringPiece(engine.encoding), image_search_branding_label,
alternate_urls,
ToStringPiece(engine.preconnect_to_search_url) == "ALLOWED",
ToStringPiece(engine.prefetch_likely_navigations) == "ALLOWED",
engine.id);
}
std::unique_ptr<TemplateURLData> TemplateURLDataFromOverrideDictionary(
const base::Value::Dict& engine_dict) {
const std::string* string_value = nullptr;
std::u16string name;
std::u16string keyword;
std::string search_url;
std::string favicon_url;
std::string encoding;
string_value = engine_dict.FindString("name");
if (string_value) {
name = base::UTF8ToUTF16(*string_value);
}
string_value = engine_dict.FindString("keyword");
if (string_value) {
keyword = base::UTF8ToUTF16(*string_value);
}
string_value = engine_dict.FindString("search_url");
if (string_value) {
search_url = *string_value;
}
string_value = engine_dict.FindString("favicon_url");
if (string_value) {
favicon_url = *string_value;
}
string_value = engine_dict.FindString("encoding");
if (string_value) {
encoding = *string_value;
}
std::optional<int> id = engine_dict.FindInt("id");
// The following fields are required for each search engine configuration.
if (!name.empty() && !keyword.empty() && !search_url.empty() &&
!favicon_url.empty() && !encoding.empty() && id.has_value()) {
// These fields are optional.
base::Value::List empty_list;
const base::Value::List* alternate_urls =
engine_dict.FindList("alternate_urls");
if (!alternate_urls)
alternate_urls = &empty_list;
std::string suggest_url;
std::string image_url;
std::string image_translate_url;
std::string new_tab_url;
std::string contextual_search_url;
std::string logo_url;
std::string doodle_url;
std::string search_url_post_params;
std::string suggest_url_post_params;
std::string image_url_post_params;
std::string side_search_param;
std::string side_image_search_param;
std::string image_translate_source_language_param_key;
std::string image_translate_target_language_param_key;
std::u16string image_search_branding_label;
std::vector<std::string> search_intent_params;
std::string preconnect_to_search_url;
std::string prefetch_likely_navigations;
string_value = engine_dict.FindString("suggest_url");
if (string_value) {
suggest_url = *string_value;
}
string_value = engine_dict.FindString("image_url");
if (string_value) {
image_url = *string_value;
}
string_value = engine_dict.FindString("image_translate_url");
if (string_value) {
image_translate_url = *string_value;
}
string_value = engine_dict.FindString("new_tab_url");
if (string_value) {
new_tab_url = *string_value;
}
string_value = engine_dict.FindString("contextual_search_url");
if (string_value) {
contextual_search_url = *string_value;
}
string_value = engine_dict.FindString("logo_url");
if (string_value) {
logo_url = *string_value;
}
string_value = engine_dict.FindString("doodle_url");
if (string_value) {
doodle_url = *string_value;
}
string_value = engine_dict.FindString("search_url_post_params");
if (string_value) {
search_url_post_params = *string_value;
}
string_value = engine_dict.FindString("suggest_url_post_params");
if (string_value) {
suggest_url_post_params = *string_value;
}
string_value = engine_dict.FindString("image_url_post_params");
if (string_value) {
image_url_post_params = *string_value;
}
string_value = engine_dict.FindString("side_search_param");
if (string_value) {
side_search_param = *string_value;
}
string_value = engine_dict.FindString("side_image_search_param");
if (string_value) {
side_image_search_param = *string_value;
}
string_value =
engine_dict.FindString("image_translate_source_language_param_key");
if (string_value) {
image_translate_source_language_param_key = *string_value;
}
string_value =
engine_dict.FindString("image_translate_target_language_param_key");
if (string_value) {
image_translate_target_language_param_key = *string_value;
}
string_value = engine_dict.FindString("image_search_branding_label");
if (string_value) {
image_search_branding_label = base::UTF8ToUTF16(*string_value);
}
const base::Value::List* additional_params_list =
engine_dict.FindList(DefaultSearchManager::kSearchIntentParams);
if (additional_params_list) {
for (const auto& additional_param_value : *additional_params_list) {
const auto* additional_param = additional_param_value.GetIfString();
if (additional_param && !additional_param->empty()) {
search_intent_params.push_back(*additional_param);
}
}
}
string_value = engine_dict.FindString("preconnect_to_search_url");
if (string_value) {
preconnect_to_search_url = *string_value;
}
string_value = engine_dict.FindString("prefetch_likely_navigations");
if (string_value) {
prefetch_likely_navigations = *string_value;
}
return std::make_unique<TemplateURLData>(
name, keyword, search_url, suggest_url, image_url, image_translate_url,
new_tab_url, contextual_search_url, logo_url, doodle_url,
search_url_post_params, suggest_url_post_params, image_url_post_params,
side_search_param, side_image_search_param,
image_translate_source_language_param_key,
image_translate_target_language_param_key,
std::move(search_intent_params), favicon_url, encoding,
image_search_branding_label, *alternate_urls,
preconnect_to_search_url.compare("ALLOWED") == 0,
prefetch_likely_navigations.compare("ALLOWED") == 0, *id);
}
return nullptr;
}
std::unique_ptr<TemplateURLData> TemplateURLDataFromStarterPackEngine(
const TemplateURLStarterPackData::StarterPackEngine& engine) {
auto turl = std::make_unique<TemplateURLData>();
turl->SetShortName(l10n_util::GetStringUTF16(engine.name_message_id));
turl->SetKeyword(u"@" + l10n_util::GetStringUTF16(engine.keyword_message_id));
turl->SetURL(engine.search_url);
turl->favicon_url = GURL(ToStringPiece(engine.favicon_url));
turl->starter_pack_id = engine.id;
turl->GenerateSyncGUID();
turl->safe_for_autoreplace = true;
turl->is_active = TemplateURLData::ActiveStatus::kTrue;
return turl;
}