1 // Copyright 2016 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "components/search_engines/template_url_data_util.h"
9 #include "base/strings/string_number_conversions.h"
10 #include "base/strings/string_piece.h"
11 #include "base/strings/utf_string_conversions.h"
12 #include "base/values.h"
13 #include "components/search_engines/default_search_manager.h"
14 #include "components/search_engines/prepopulated_engines.h"
15 #include "components/search_engines/template_url_data.h"
16 #include "components/search_engines/template_url_starter_pack_data.h"
17 #include "ui/base/l10n/l10n_util.h"
22 // Converts the C-style string `str` to a base::StringPiece making sure to avoid
23 // dereferencing nullptrs.
24 base::StringPiece ToStringPiece(const char* str) {
25 return str ? base::StringPiece(str) : base::StringPiece();
30 std::unique_ptr<TemplateURLData> TemplateURLDataFromDictionary(
31 const base::Value::Dict& dict) {
32 const std::string* search_url = dict.FindString(DefaultSearchManager::kURL);
33 const std::string* keyword = dict.FindString(DefaultSearchManager::kKeyword);
34 const std::string* short_name =
35 dict.FindString(DefaultSearchManager::kShortName);
36 // Check required TemplateURLData fields first.
37 if (!search_url || !keyword || !short_name) {
41 auto result = std::make_unique<TemplateURLData>();
42 result->SetKeyword(base::UTF8ToUTF16(*keyword));
43 result->SetURL(*search_url);
45 const std::string* id = dict.FindString(DefaultSearchManager::kID);
47 base::StringToInt64(*id, &result->id);
50 const std::string* string_value = nullptr;
52 result->SetShortName(base::UTF8ToUTF16(*short_name));
53 result->prepopulate_id = dict.FindInt(DefaultSearchManager::kPrepopulateID)
54 .value_or(result->prepopulate_id);
55 result->starter_pack_id = dict.FindInt(DefaultSearchManager::kStarterPackId)
56 .value_or(result->starter_pack_id);
57 string_value = dict.FindString(DefaultSearchManager::kSyncGUID);
59 result->sync_guid = *string_value;
61 string_value = dict.FindString(DefaultSearchManager::kSuggestionsURL);
63 result->suggestions_url = *string_value;
66 string_value = dict.FindString(DefaultSearchManager::kImageURL);
68 result->image_url = *string_value;
70 string_value = dict.FindString(DefaultSearchManager::kImageTranslateURL);
72 result->image_translate_url = *string_value;
74 string_value = dict.FindString(DefaultSearchManager::kNewTabURL);
76 result->new_tab_url = *string_value;
78 string_value = dict.FindString(DefaultSearchManager::kContextualSearchURL);
80 result->contextual_search_url = *string_value;
83 string_value = dict.FindString(DefaultSearchManager::kFaviconURL);
85 result->favicon_url = GURL(*string_value);
87 string_value = dict.FindString(DefaultSearchManager::kOriginatingURL);
89 result->originating_url = GURL(*string_value);
91 string_value = dict.FindString(DefaultSearchManager::kLogoURL);
93 result->logo_url = GURL(*string_value);
95 string_value = dict.FindString(DefaultSearchManager::kDoodleURL);
97 result->doodle_url = GURL(*string_value);
100 const std::string* search_url_post_params =
101 dict.FindString(DefaultSearchManager::kSearchURLPostParams);
102 if (search_url_post_params) {
103 result->search_url_post_params = *search_url_post_params;
105 const std::string* suggestions_url_post_params =
106 dict.FindString(DefaultSearchManager::kSuggestionsURLPostParams);
107 if (suggestions_url_post_params) {
108 result->suggestions_url_post_params = *suggestions_url_post_params;
110 const std::string* image_url_post_params =
111 dict.FindString(DefaultSearchManager::kImageURLPostParams);
112 if (image_url_post_params) {
113 result->image_url_post_params = *image_url_post_params;
115 const std::string* side_search_param =
116 dict.FindString(DefaultSearchManager::kSideSearchParam);
117 if (side_search_param) {
118 result->side_search_param = *side_search_param;
120 const std::string* side_image_search_param =
121 dict.FindString(DefaultSearchManager::kSideImageSearchParam);
122 if (side_image_search_param) {
123 result->side_image_search_param = *side_image_search_param;
125 const std::string* image_translate_source_language_param_key =
127 DefaultSearchManager::kImageTranslateSourceLanguageParamKey);
128 if (image_translate_source_language_param_key) {
129 result->image_translate_source_language_param_key =
130 *image_translate_source_language_param_key;
132 const std::string* image_translate_target_language_param_key =
134 DefaultSearchManager::kImageTranslateTargetLanguageParamKey);
135 if (image_translate_target_language_param_key) {
136 result->image_translate_target_language_param_key =
137 *image_translate_target_language_param_key;
139 const std::string* image_search_branding_label =
140 dict.FindString(DefaultSearchManager::kImageSearchBrandingLabel);
141 if (image_search_branding_label) {
142 result->image_search_branding_label =
143 base::UTF8ToUTF16(*image_search_branding_label);
145 const base::Value::List* additional_params_list =
146 dict.FindList(DefaultSearchManager::kSearchIntentParams);
147 if (additional_params_list) {
148 for (const auto& additional_param_value : *additional_params_list) {
149 const auto* additional_param = additional_param_value.GetIfString();
150 DCHECK(additional_param && !additional_param->empty());
151 if (additional_param && !additional_param->empty()) {
152 result->search_intent_params.push_back(*additional_param);
156 absl::optional<bool> safe_for_autoreplace =
157 dict.FindBool(DefaultSearchManager::kSafeForAutoReplace);
158 if (safe_for_autoreplace) {
159 result->safe_for_autoreplace = *safe_for_autoreplace;
162 std::string date_created_str;
163 std::string last_modified_str;
164 std::string last_visited_str;
166 string_value = dict.FindString(DefaultSearchManager::kDateCreated);
168 date_created_str = *string_value;
170 string_value = dict.FindString(DefaultSearchManager::kLastModified);
172 last_modified_str = *string_value;
174 string_value = dict.FindString(DefaultSearchManager::kLastVisited);
176 last_visited_str = *string_value;
179 int64_t date_created = 0;
180 if (base::StringToInt64(date_created_str, &date_created))
181 result->date_created = base::Time::FromInternalValue(date_created);
183 int64_t last_modified = 0;
184 if (base::StringToInt64(last_modified_str, &last_modified))
185 result->last_modified = base::Time::FromInternalValue(last_modified);
187 int64_t last_visited = 0;
188 if (base::StringToInt64(last_visited_str, &last_visited))
189 result->last_visited = base::Time::FromInternalValue(last_visited);
191 result->usage_count = dict.FindInt(DefaultSearchManager::kUsageCount)
192 .value_or(result->usage_count);
194 const base::Value::List* alternate_urls =
195 dict.FindList(DefaultSearchManager::kAlternateURLs);
196 if (alternate_urls) {
197 for (const auto& it : *alternate_urls) {
199 result->alternate_urls.push_back(it.GetString());
203 const base::Value::List* encodings =
204 dict.FindList(DefaultSearchManager::kInputEncodings);
206 for (const auto& it : *encodings) {
207 std::string encoding;
209 result->input_encodings.push_back(it.GetString());
213 result->created_by_policy =
214 dict.FindBool(DefaultSearchManager::kCreatedByPolicy)
215 .value_or(result->created_by_policy);
216 result->created_from_play_api =
217 dict.FindBool(DefaultSearchManager::kCreatedFromPlayAPI)
218 .value_or(result->created_from_play_api);
219 result->preconnect_to_search_url =
220 dict.FindBool(DefaultSearchManager::kPreconnectToSearchUrl)
221 .value_or(result->preconnect_to_search_url);
222 result->prefetch_likely_navigations =
223 dict.FindBool(DefaultSearchManager::kPrefetchLikelyNavigations)
224 .value_or(result->prefetch_likely_navigations);
225 result->is_active = static_cast<TemplateURLData::ActiveStatus>(
226 dict.FindInt(DefaultSearchManager::kIsActive)
227 .value_or(static_cast<int>(result->is_active)));
228 result->enforced_by_policy =
229 dict.FindBool(DefaultSearchManager::kEnforcedByPolicy)
230 .value_or(result->enforced_by_policy);
234 base::Value::Dict TemplateURLDataToDictionary(const TemplateURLData& data) {
235 base::Value::Dict url_dict;
236 url_dict.Set(DefaultSearchManager::kID, base::NumberToString(data.id));
237 url_dict.Set(DefaultSearchManager::kShortName, data.short_name());
238 url_dict.Set(DefaultSearchManager::kKeyword, data.keyword());
239 url_dict.Set(DefaultSearchManager::kPrepopulateID, data.prepopulate_id);
240 url_dict.Set(DefaultSearchManager::kStarterPackId, data.starter_pack_id);
241 url_dict.Set(DefaultSearchManager::kSyncGUID, data.sync_guid);
243 url_dict.Set(DefaultSearchManager::kURL, data.url());
244 url_dict.Set(DefaultSearchManager::kSuggestionsURL, data.suggestions_url);
245 url_dict.Set(DefaultSearchManager::kImageURL, data.image_url);
246 url_dict.Set(DefaultSearchManager::kImageTranslateURL,
247 data.image_translate_url);
248 url_dict.Set(DefaultSearchManager::kNewTabURL, data.new_tab_url);
249 url_dict.Set(DefaultSearchManager::kContextualSearchURL,
250 data.contextual_search_url);
251 url_dict.Set(DefaultSearchManager::kFaviconURL, data.favicon_url.spec());
252 url_dict.Set(DefaultSearchManager::kOriginatingURL,
253 data.originating_url.spec());
254 url_dict.Set(DefaultSearchManager::kLogoURL, data.logo_url.spec());
255 url_dict.Set(DefaultSearchManager::kDoodleURL, data.doodle_url.spec());
257 url_dict.Set(DefaultSearchManager::kSearchURLPostParams,
258 data.search_url_post_params);
259 url_dict.Set(DefaultSearchManager::kSuggestionsURLPostParams,
260 data.suggestions_url_post_params);
261 url_dict.Set(DefaultSearchManager::kImageURLPostParams,
262 data.image_url_post_params);
263 url_dict.Set(DefaultSearchManager::kSideSearchParam, data.side_search_param);
264 url_dict.Set(DefaultSearchManager::kSideImageSearchParam,
265 data.side_image_search_param);
266 url_dict.Set(DefaultSearchManager::kImageTranslateSourceLanguageParamKey,
267 data.image_translate_source_language_param_key);
268 url_dict.Set(DefaultSearchManager::kImageTranslateTargetLanguageParamKey,
269 data.image_translate_target_language_param_key);
270 url_dict.Set(DefaultSearchManager::kImageSearchBrandingLabel,
271 data.image_search_branding_label);
273 base::Value::List additional_params_list;
274 for (const auto& additional_param : data.search_intent_params) {
275 additional_params_list.Append(additional_param);
277 url_dict.Set(DefaultSearchManager::kSearchIntentParams,
278 std::move(additional_params_list));
280 url_dict.Set(DefaultSearchManager::kSafeForAutoReplace,
281 data.safe_for_autoreplace);
283 url_dict.Set(DefaultSearchManager::kDateCreated,
284 base::NumberToString(data.date_created.ToInternalValue()));
285 url_dict.Set(DefaultSearchManager::kLastModified,
286 base::NumberToString(data.last_modified.ToInternalValue()));
287 url_dict.Set(DefaultSearchManager::kLastVisited,
288 base::NumberToString(data.last_visited.ToInternalValue()));
289 url_dict.Set(DefaultSearchManager::kUsageCount, data.usage_count);
291 base::Value::List alternate_urls;
292 for (const auto& alternate_url : data.alternate_urls)
293 alternate_urls.Append(alternate_url);
295 url_dict.Set(DefaultSearchManager::kAlternateURLs, std::move(alternate_urls));
297 base::Value::List encodings;
298 for (const auto& input_encoding : data.input_encodings)
299 encodings.Append(input_encoding);
300 url_dict.Set(DefaultSearchManager::kInputEncodings, std::move(encodings));
302 url_dict.Set(DefaultSearchManager::kCreatedByPolicy, data.created_by_policy);
303 url_dict.Set(DefaultSearchManager::kCreatedFromPlayAPI,
304 data.created_from_play_api);
305 url_dict.Set(DefaultSearchManager::kPreconnectToSearchUrl,
306 data.preconnect_to_search_url);
307 url_dict.Set(DefaultSearchManager::kPrefetchLikelyNavigations,
308 data.prefetch_likely_navigations);
309 url_dict.Set(DefaultSearchManager::kIsActive,
310 static_cast<int>(data.is_active));
311 url_dict.Set(DefaultSearchManager::kEnforcedByPolicy,
312 data.enforced_by_policy);
316 std::unique_ptr<TemplateURLData> TemplateURLDataFromPrepopulatedEngine(
317 const TemplateURLPrepopulateData::PrepopulatedEngine& engine) {
318 std::vector<std::string> search_intent_params;
319 if (engine.search_intent_params) {
320 for (size_t i = 0; i < engine.search_intent_params_size; ++i) {
321 search_intent_params.emplace_back(engine.search_intent_params[i]);
325 base::Value::List alternate_urls;
326 if (engine.alternate_urls) {
327 for (size_t i = 0; i < engine.alternate_urls_size; ++i)
328 alternate_urls.Append(std::string(engine.alternate_urls[i]));
331 std::u16string image_search_branding_label =
332 engine.image_search_branding_label
333 ? base::WideToUTF16(engine.image_search_branding_label)
336 return std::make_unique<TemplateURLData>(
337 base::WideToUTF16(engine.name), base::WideToUTF16(engine.keyword),
338 ToStringPiece(engine.search_url), ToStringPiece(engine.suggest_url),
339 ToStringPiece(engine.image_url),
340 ToStringPiece(engine.image_translate_url),
341 ToStringPiece(engine.new_tab_url),
342 ToStringPiece(engine.contextual_search_url),
343 ToStringPiece(engine.logo_url), ToStringPiece(engine.doodle_url),
344 ToStringPiece(engine.search_url_post_params),
345 ToStringPiece(engine.suggest_url_post_params),
346 ToStringPiece(engine.image_url_post_params),
347 ToStringPiece(engine.side_search_param),
348 ToStringPiece(engine.side_image_search_param),
349 ToStringPiece(engine.image_translate_source_language_param_key),
350 ToStringPiece(engine.image_translate_target_language_param_key),
351 std::move(search_intent_params), ToStringPiece(engine.favicon_url),
352 ToStringPiece(engine.encoding), image_search_branding_label,
354 ToStringPiece(engine.preconnect_to_search_url) == "ALLOWED",
355 ToStringPiece(engine.prefetch_likely_navigations) == "ALLOWED",
359 std::unique_ptr<TemplateURLData> TemplateURLDataFromOverrideDictionary(
360 const base::Value::Dict& engine_dict) {
361 const std::string* string_value = nullptr;
364 std::u16string keyword;
365 std::string search_url;
366 std::string favicon_url;
367 std::string encoding;
369 string_value = engine_dict.FindString("name");
371 name = base::UTF8ToUTF16(*string_value);
373 string_value = engine_dict.FindString("keyword");
375 keyword = base::UTF8ToUTF16(*string_value);
377 string_value = engine_dict.FindString("search_url");
379 search_url = *string_value;
381 string_value = engine_dict.FindString("favicon_url");
383 favicon_url = *string_value;
385 string_value = engine_dict.FindString("encoding");
387 encoding = *string_value;
389 absl::optional<int> id = engine_dict.FindInt("id");
391 // The following fields are required for each search engine configuration.
392 if (!name.empty() && !keyword.empty() && !search_url.empty() &&
393 !favicon_url.empty() && !encoding.empty() && id.has_value()) {
394 // These fields are optional.
395 base::Value::List empty_list;
396 const base::Value::List* alternate_urls =
397 engine_dict.FindList("alternate_urls");
399 alternate_urls = &empty_list;
401 std::string suggest_url;
402 std::string image_url;
403 std::string image_translate_url;
404 std::string new_tab_url;
405 std::string contextual_search_url;
406 std::string logo_url;
407 std::string doodle_url;
408 std::string search_url_post_params;
409 std::string suggest_url_post_params;
410 std::string image_url_post_params;
411 std::string side_search_param;
412 std::string side_image_search_param;
413 std::string image_translate_source_language_param_key;
414 std::string image_translate_target_language_param_key;
415 std::u16string image_search_branding_label;
416 std::vector<std::string> search_intent_params;
417 std::string preconnect_to_search_url;
418 std::string prefetch_likely_navigations;
420 string_value = engine_dict.FindString("suggest_url");
422 suggest_url = *string_value;
424 string_value = engine_dict.FindString("image_url");
426 image_url = *string_value;
428 string_value = engine_dict.FindString("image_translate_url");
430 image_translate_url = *string_value;
432 string_value = engine_dict.FindString("new_tab_url");
434 new_tab_url = *string_value;
436 string_value = engine_dict.FindString("contextual_search_url");
438 contextual_search_url = *string_value;
440 string_value = engine_dict.FindString("logo_url");
442 logo_url = *string_value;
444 string_value = engine_dict.FindString("doodle_url");
446 doodle_url = *string_value;
448 string_value = engine_dict.FindString("search_url_post_params");
450 search_url_post_params = *string_value;
452 string_value = engine_dict.FindString("suggest_url_post_params");
454 suggest_url_post_params = *string_value;
456 string_value = engine_dict.FindString("image_url_post_params");
458 image_url_post_params = *string_value;
460 string_value = engine_dict.FindString("side_search_param");
462 side_search_param = *string_value;
464 string_value = engine_dict.FindString("side_image_search_param");
466 side_image_search_param = *string_value;
469 engine_dict.FindString("image_translate_source_language_param_key");
471 image_translate_source_language_param_key = *string_value;
474 engine_dict.FindString("image_translate_target_language_param_key");
476 image_translate_target_language_param_key = *string_value;
478 string_value = engine_dict.FindString("image_search_branding_label");
480 image_search_branding_label = base::UTF8ToUTF16(*string_value);
482 const base::Value::List* additional_params_list =
483 engine_dict.FindList(DefaultSearchManager::kSearchIntentParams);
484 if (additional_params_list) {
485 for (const auto& additional_param_value : *additional_params_list) {
486 const auto* additional_param = additional_param_value.GetIfString();
487 if (additional_param && !additional_param->empty()) {
488 search_intent_params.push_back(*additional_param);
492 string_value = engine_dict.FindString("preconnect_to_search_url");
494 preconnect_to_search_url = *string_value;
496 string_value = engine_dict.FindString("prefetch_likely_navigations");
498 prefetch_likely_navigations = *string_value;
501 return std::make_unique<TemplateURLData>(
502 name, keyword, search_url, suggest_url, image_url, image_translate_url,
503 new_tab_url, contextual_search_url, logo_url, doodle_url,
504 search_url_post_params, suggest_url_post_params, image_url_post_params,
505 side_search_param, side_image_search_param,
506 image_translate_source_language_param_key,
507 image_translate_target_language_param_key,
508 std::move(search_intent_params), favicon_url, encoding,
509 image_search_branding_label, *alternate_urls,
510 preconnect_to_search_url.compare("ALLOWED") == 0,
511 prefetch_likely_navigations.compare("ALLOWED") == 0, *id);
516 std::unique_ptr<TemplateURLData> TemplateURLDataFromStarterPackEngine(
517 const TemplateURLStarterPackData::StarterPackEngine& engine) {
518 auto turl = std::make_unique<TemplateURLData>();
519 turl->SetShortName(l10n_util::GetStringUTF16(engine.name_message_id));
520 turl->SetKeyword(u"@" + l10n_util::GetStringUTF16(engine.keyword_message_id));
521 turl->SetURL(engine.search_url);
522 turl->favicon_url = GURL(ToStringPiece(engine.favicon_url));
523 turl->starter_pack_id = engine.id;
524 turl->GenerateSyncGUID();
525 turl->safe_for_autoreplace = true;
526 turl->is_active = TemplateURLData::ActiveStatus::kTrue;