1 // Copyright 2014 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "components/search_engines/template_url_service.h"
6 
7 #include <algorithm>
8 
9 #include "base/auto_reset.h"
10 #include "base/base64.h"
11 #include "base/base64url.h"
12 #include "base/bind.h"
13 #include "base/callback.h"
14 #include "base/debug/crash_logging.h"
15 #include "base/format_macros.h"
16 #include "base/metrics/histogram_macros.h"
17 #include "base/rand_util.h"
18 #include "base/stl_util.h"
19 #include "base/strings/string_split.h"
20 #include "base/strings/string_util.h"
21 #include "base/strings/utf_string_conversions.h"
22 #include "components/pref_registry/pref_registry_syncable.h"
23 #include "components/prefs/pref_service.h"
24 #include "components/search_engines/search_engines_pref_names.h"
25 #include "components/search_engines/search_terms_data.h"
26 #include "components/search_engines/template_url_prepopulate_data.h"
27 #include "components/search_engines/template_url_service_client.h"
28 #include "components/search_engines/template_url_service_observer.h"
29 #include "components/search_engines/util.h"
30 #include "components/sync/model/sync_change.h"
31 #include "components/sync/model/sync_change_processor.h"
32 #include "components/sync/model/sync_error_factory.h"
33 #include "components/sync/protocol/search_engine_specifics.pb.h"
34 #include "components/sync/protocol/sync.pb.h"
35 #include "components/url_formatter/url_fixer.h"
36 #include "components/variations/variations_associated_data.h"
37 #include "net/base/registry_controlled_domains/registry_controlled_domain.h"
38 #include "url/gurl.h"
39 
40 #if defined(OS_ANDROID)
41 #include "components/search_engines/android/template_url_service_android.h"
42 #endif
43 
44 typedef SearchHostToURLsMap::TemplateURLSet TemplateURLSet;
45 typedef TemplateURLService::SyncDataMap SyncDataMap;
46 
47 namespace {
48 
49 const char kDeleteSyncedEngineHistogramName[] =
50     "Search.DeleteSyncedSearchEngine";
51 
52 // Values for an enumerated histogram used to track whenever an ACTION_DELETE is
53 // sent to the server for search engines. These are persisted. Do not re-number.
54 enum DeleteSyncedSearchEngineEvent {
55   DELETE_ENGINE_USER_ACTION = 0,
56   DELETE_ENGINE_PRE_SYNC = 1,
57   DELETE_ENGINE_EMPTY_FIELD = 2,
58   DELETE_ENGINE_MAX,
59 };
60 
61 const char kSearchTemplateURLEventsHistogramName[] =
62     "Search.TemplateURL.Events";
63 
64 // Values for an enumerated histogram used to track TemplateURL edge cases.
65 // These are persisted. Do not re-number.
66 enum SearchTemplateURLEvent {
67   SYNC_DELETE_SUCCESS = 0,
68   SYNC_DELETE_FAIL_NONEXISTENT_ENGINE = 1,
69   SYNC_DELETE_FAIL_DEFAULT_SEARCH_PROVIDER = 2,
70   SEARCH_TEMPLATE_URL_EVENT_MAX,
71 };
72 
73 // Returns true iff the change in |change_list| at index |i| should not be sent
74 // up to the server based on its GUIDs presence in |sync_data| or when compared
75 // to changes after it in |change_list|.
76 // The criteria is:
77 //  1) It is an ACTION_UPDATE or ACTION_DELETE and the sync_guid associated
78 //     with it is NOT found in |sync_data|. We can only update and remove
79 //     entries that were originally from the Sync server.
80 //  2) It is an ACTION_ADD and the sync_guid associated with it is found in
81 //     |sync_data|. We cannot re-add entries that Sync already knew about.
82 //  3) There is an update after an update for the same GUID. We prune earlier
83 //     ones just to save bandwidth (Sync would normally coalesce them).
ShouldRemoveSyncChange(size_t index,syncer::SyncChangeList * change_list,const SyncDataMap * sync_data)84 bool ShouldRemoveSyncChange(size_t index,
85                             syncer::SyncChangeList* change_list,
86                             const SyncDataMap* sync_data) {
87   DCHECK(index < change_list->size());
88   const syncer::SyncChange& change_i = (*change_list)[index];
89   const std::string guid = change_i.sync_data().GetSpecifics()
90       .search_engine().sync_guid();
91   syncer::SyncChange::SyncChangeType type = change_i.change_type();
92   if ((type == syncer::SyncChange::ACTION_UPDATE ||
93        type == syncer::SyncChange::ACTION_DELETE) &&
94        sync_data->find(guid) == sync_data->end())
95     return true;
96   if (type == syncer::SyncChange::ACTION_ADD &&
97       sync_data->find(guid) != sync_data->end())
98     return true;
99   if (type == syncer::SyncChange::ACTION_UPDATE) {
100     for (size_t j = index + 1; j < change_list->size(); j++) {
101       const syncer::SyncChange& change_j = (*change_list)[j];
102       if ((syncer::SyncChange::ACTION_UPDATE == change_j.change_type()) &&
103           (change_j.sync_data().GetSpecifics().search_engine().sync_guid() ==
104               guid))
105         return true;
106     }
107   }
108   return false;
109 }
110 
111 // Remove SyncChanges that should not be sent to the server from |change_list|.
112 // This is done to eliminate incorrect SyncChanges added by the merge and
113 // conflict resolution logic when it is unsure of whether or not an entry is new
114 // from Sync or originally from the local model. This also removes changes that
115 // would be otherwise be coalesced by Sync in order to save bandwidth.
PruneSyncChanges(const SyncDataMap * sync_data,syncer::SyncChangeList * change_list)116 void PruneSyncChanges(const SyncDataMap* sync_data,
117                       syncer::SyncChangeList* change_list) {
118   for (size_t i = 0; i < change_list->size(); ) {
119     if (ShouldRemoveSyncChange(i, change_list, sync_data))
120       change_list->erase(change_list->begin() + i);
121     else
122       ++i;
123   }
124 }
125 
126 // Returns true if |turl|'s GUID is not found inside |sync_data|. This is to be
127 // used in MergeDataAndStartSyncing to differentiate between TemplateURLs from
128 // Sync and TemplateURLs that were initially local, assuming |sync_data| is the
129 // |initial_sync_data| parameter.
IsFromSync(const TemplateURL * turl,const SyncDataMap & sync_data)130 bool IsFromSync(const TemplateURL* turl, const SyncDataMap& sync_data) {
131   return base::Contains(sync_data, turl->sync_guid());
132 }
133 
134 // Log the number of instances of a keyword that exist, with zero or more
135 // underscores, which could occur as the result of conflict resolution.
LogDuplicatesHistogram(const TemplateURLService::TemplateURLVector & template_urls)136 void LogDuplicatesHistogram(
137     const TemplateURLService::TemplateURLVector& template_urls) {
138   std::map<base::string16, int> duplicates;
139   for (auto it = template_urls.begin(); it != template_urls.end(); ++it) {
140     base::string16 keyword = (*it)->keyword();
141     base::TrimString(keyword, base::ASCIIToUTF16("_"), &keyword);
142     duplicates[keyword]++;
143   }
144 
145   // Count the keywords with duplicates.
146   int num_dupes = 0;
147   for (std::map<base::string16, int>::const_iterator it = duplicates.begin();
148        it != duplicates.end(); ++it) {
149     if (it->second > 1)
150       num_dupes++;
151   }
152 
153   UMA_HISTOGRAM_COUNTS_100("Search.SearchEngineDuplicateCounts", num_dupes);
154 }
155 
156 // Returns the length of the registry portion of a hostname.  For example,
157 // www.google.co.uk will return 5 (the length of co.uk).
GetRegistryLength(const base::string16 & host)158 size_t GetRegistryLength(const base::string16& host) {
159   return net::registry_controlled_domains::PermissiveGetHostRegistryLength(
160       host, net::registry_controlled_domains::EXCLUDE_UNKNOWN_REGISTRIES,
161       net::registry_controlled_domains::EXCLUDE_PRIVATE_REGISTRIES);
162 }
163 
164 // For keywords that look like hostnames, returns whether KeywordProvider
165 // should require users to type a prefix of the hostname to match against
166 // them, rather than just the domain name portion. In other words, returns
167 // whether the prefix before the domain name should be considered important
168 // for matching purposes. Returns true if the experiment isn't active.
OmniboxFieldTrialKeywordRequiresRegistry()169 bool OmniboxFieldTrialKeywordRequiresRegistry() {
170   // This would normally be
171   // bool OmniboxFieldTrial::KeywordRequiresRegistry()
172   // but that would create a dependency cycle since omnibox depends on
173   // search_engines (and search -> search_engines)
174   constexpr char kBundledExperimentFieldTrialName[] =
175       "OmniboxBundledExperimentV1";
176   constexpr char kKeywordRequiresRegistryRule[] = "KeywordRequiresRegistry";
177   const std::string value = variations::GetVariationParamValue(
178       kBundledExperimentFieldTrialName, kKeywordRequiresRegistryRule);
179   return value.empty() || (value == "true");
180 }
181 
182 // Returns the length of the important part of the |keyword|, assumed to be
183 // associated with the TemplateURL.  For instance, for the keyword
184 // google.co.uk, this can return 6 (the length of "google").
GetMeaningfulKeywordLength(const base::string16 & keyword,const TemplateURL * turl)185 size_t GetMeaningfulKeywordLength(const base::string16& keyword,
186                                   const TemplateURL* turl) {
187   // Using Omnibox from here is a layer violation and should be fixed.
188   if (OmniboxFieldTrialKeywordRequiresRegistry())
189     return keyword.length();
190   const size_t registry_length = GetRegistryLength(keyword);
191   if (registry_length == std::string::npos)
192     return keyword.length();
193   DCHECK_LT(registry_length, keyword.length());
194   // The meaningful keyword length is the length of any portion before the
195   // registry ("co.uk") and its preceding dot.
196   return keyword.length() - (registry_length ? (registry_length + 1) : 0);
197 }
198 
Contains(TemplateURLService::OwnedTemplateURLVector * template_urls,const TemplateURL * turl)199 bool Contains(TemplateURLService::OwnedTemplateURLVector* template_urls,
200               const TemplateURL* turl) {
201   return FindTemplateURL(template_urls, turl) != template_urls->end();
202 }
203 
IsCreatedByExtension(const TemplateURL * template_url)204 bool IsCreatedByExtension(const TemplateURL* template_url) {
205   return template_url->type() ==
206              TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION ||
207          template_url->type() == TemplateURL::OMNIBOX_API_EXTENSION;
208 }
209 
210 }  // namespace
211 
212 // TemplateURLService::LessWithPrefix -----------------------------------------
213 
214 class TemplateURLService::LessWithPrefix {
215  public:
216   // We want to find the set of keywords that begin with a prefix.  The STL
217   // algorithms will return the set of elements that are "equal to" the
218   // prefix, where "equal(x, y)" means "!(cmp(x, y) || cmp(y, x))".  When
219   // cmp() is the typical std::less<>, this results in lexicographic equality;
220   // we need to extend this to mark a prefix as "not less than" a keyword it
221   // begins, which will cause the desired elements to be considered "equal to"
222   // the prefix.  Note: this is still a strict weak ordering, as required by
223   // equal_range() (though I will not prove that here).
224   //
225   // Unfortunately the calling convention is not "prefix and element" but
226   // rather "two elements", so we pass the prefix as a fake "element" which has
227   // a NULL KeywordDataElement pointer.
operator ()(const KeywordToTURLAndMeaningfulLength::value_type & elem1,const KeywordToTURLAndMeaningfulLength::value_type & elem2) const228   bool operator()(
229       const KeywordToTURLAndMeaningfulLength::value_type& elem1,
230       const KeywordToTURLAndMeaningfulLength::value_type& elem2) const {
231     return (elem1.second.first == nullptr)
232                ? (elem2.first.compare(0, elem1.first.length(), elem1.first) > 0)
233                : (elem1.first < elem2.first);
234   }
235 };
236 
237 // TemplateURLService::Scoper -------------------------------------------------
238 
239 class TemplateURLService::Scoper {
240  public:
241   // Keep one of these handles in scope to coalesce all the notifications into a
242   // single notification. Likewise, BatchModeScoper defers web data service
243   // operations into a batch operation.
244   //
245   // Notifications are sent when the last outstanding handle is destroyed and
246   // |model_mutated_notification_pending_| is true.
247   //
248   // The web data service batch operation is performed when the batch mode level
249   // is 0 and more than one operation is pending. This check happens when
250   // BatchModeScoper is destroyed.
Scoper(TemplateURLService * service)251   explicit Scoper(TemplateURLService* service)
252       : batch_mode_scoper_(
253             std::make_unique<KeywordWebDataService::BatchModeScoper>(
254                 service->web_data_service_.get())),
255         service_(service) {
256     ++service_->outstanding_scoper_handles_;
257   }
258 
259   // When a Scoper is destroyed, the handle count is updated. If the handle
260   // count is at zero, notify the observers that the model has changed if
261   // service is loaded and model was mutated.
~Scoper()262   ~Scoper() {
263     DCHECK_GT(service_->outstanding_scoper_handles_, 0);
264 
265     --service_->outstanding_scoper_handles_;
266     if (service_->outstanding_scoper_handles_ == 0 &&
267         service_->model_mutated_notification_pending_) {
268       service_->model_mutated_notification_pending_ = false;
269 
270       if (!service_->loaded_)
271         return;
272 
273       for (auto& observer : service_->model_observers_)
274         observer.OnTemplateURLServiceChanged();
275     }
276   }
277 
278  private:
279   std::unique_ptr<KeywordWebDataService::BatchModeScoper> batch_mode_scoper_;
280   TemplateURLService* service_;
281 
282   DISALLOW_COPY_AND_ASSIGN(Scoper);
283 };
284 
285 // TemplateURLService ---------------------------------------------------------
286 
TemplateURLService(PrefService * prefs,std::unique_ptr<SearchTermsData> search_terms_data,const scoped_refptr<KeywordWebDataService> & web_data_service,std::unique_ptr<TemplateURLServiceClient> client,const base::Closure & dsp_change_callback)287 TemplateURLService::TemplateURLService(
288     PrefService* prefs,
289     std::unique_ptr<SearchTermsData> search_terms_data,
290     const scoped_refptr<KeywordWebDataService>& web_data_service,
291     std::unique_ptr<TemplateURLServiceClient> client,
292     const base::Closure& dsp_change_callback)
293     : prefs_(prefs),
294       search_terms_data_(std::move(search_terms_data)),
295       web_data_service_(web_data_service),
296       client_(std::move(client)),
297       dsp_change_callback_(dsp_change_callback),
298       default_search_manager_(
299           prefs_,
300           base::BindRepeating(&TemplateURLService::ApplyDefaultSearchChange,
301                               base::Unretained(this))) {
302   DCHECK(search_terms_data_);
303   Init(nullptr, 0);
304 }
305 
TemplateURLService(const Initializer * initializers,const int count)306 TemplateURLService::TemplateURLService(const Initializer* initializers,
307                                        const int count)
308     : default_search_manager_(
309           prefs_,
310           base::BindRepeating(&TemplateURLService::ApplyDefaultSearchChange,
311                               base::Unretained(this))) {
312   Init(initializers, count);
313 }
314 
~TemplateURLService()315 TemplateURLService::~TemplateURLService() {
316   // |web_data_service_| should be deleted during Shutdown().
317   DCHECK(!web_data_service_);
318 }
319 
320 // static
RegisterProfilePrefs(user_prefs::PrefRegistrySyncable * registry)321 void TemplateURLService::RegisterProfilePrefs(
322     user_prefs::PrefRegistrySyncable* registry) {
323 #if defined(OS_IOS) || defined(OS_ANDROID)
324   uint32_t flags = PrefRegistry::NO_REGISTRATION_FLAGS;
325 #else
326   uint32_t flags = user_prefs::PrefRegistrySyncable::SYNCABLE_PREF;
327 #endif
328   registry->RegisterStringPref(prefs::kSyncedDefaultSearchProviderGUID,
329                                std::string(),
330                                flags);
331   registry->RegisterBooleanPref(prefs::kDefaultSearchProviderEnabled, true);
332   registry->RegisterBooleanPref(
333       prefs::kDefaultSearchProviderContextMenuAccessAllowed, true);
334 }
335 
336 #if defined(OS_ANDROID)
GetJavaObject()337 base::android::ScopedJavaLocalRef<jobject> TemplateURLService::GetJavaObject() {
338   if (!template_url_service_android_) {
339     template_url_service_android_ =
340         std::make_unique<TemplateUrlServiceAndroid>(this);
341   }
342   return template_url_service_android_->GetJavaObject();
343 }
344 #endif
345 
CanAddAutogeneratedKeyword(const base::string16 & keyword,const GURL & url,const TemplateURL ** template_url_to_replace)346 bool TemplateURLService::CanAddAutogeneratedKeyword(
347     const base::string16& keyword,
348     const GURL& url,
349     const TemplateURL** template_url_to_replace) {
350   DCHECK(!keyword.empty());  // This should only be called for non-empty
351                              // keywords. If we need to support empty kewords
352                              // the code needs to change slightly.
353   const TemplateURL* existing_url = GetTemplateURLForKeyword(keyword);
354   if (template_url_to_replace)
355     *template_url_to_replace = existing_url;
356   if (existing_url) {
357     // We already have a TemplateURL for this keyword. Only allow it to be
358     // replaced if the TemplateURL can be replaced.
359     return CanReplace(existing_url);
360   }
361 
362   // We don't have a TemplateURL with keyword.  We still may not allow this
363   // keyword if there's evidence we may have created this keyword before and
364   // the user renamed it (because, for instance, the keyword is a common word
365   // that may interfere with search queries).  An easy heuristic for this is
366   // whether the user has a TemplateURL that has been manually modified (e.g.,
367   // renamed) connected to the same host.
368   return !url.is_valid() || url.host().empty() ||
369       CanAddAutogeneratedKeywordForHost(url.host());
370 }
371 
IsPrepopulatedOrCreatedByPolicy(const TemplateURL * t_url) const372 bool TemplateURLService::IsPrepopulatedOrCreatedByPolicy(
373     const TemplateURL* t_url) const {
374   return (t_url->prepopulate_id() > 0 || t_url->created_by_policy() ||
375           t_url->created_from_play_api()) &&
376          t_url->SupportsReplacement(search_terms_data());
377 }
378 
ShowInDefaultList(const TemplateURL * t_url) const379 bool TemplateURLService::ShowInDefaultList(const TemplateURL* t_url) const {
380   return t_url == default_search_provider_ ||
381       IsPrepopulatedOrCreatedByPolicy(t_url);
382 }
383 
AddMatchingKeywords(const base::string16 & prefix,bool supports_replacement_only,TURLsAndMeaningfulLengths * matches)384 void TemplateURLService::AddMatchingKeywords(
385     const base::string16& prefix,
386     bool supports_replacement_only,
387     TURLsAndMeaningfulLengths* matches) {
388   AddMatchingKeywordsHelper(
389       keyword_to_turl_and_length_, prefix, supports_replacement_only, matches);
390 }
391 
GetTemplateURLForKeyword(const base::string16 & keyword)392 TemplateURL* TemplateURLService::GetTemplateURLForKeyword(
393     const base::string16& keyword) {
394   return const_cast<TemplateURL*>(
395       static_cast<const TemplateURLService*>(this)->
396           GetTemplateURLForKeyword(keyword));
397 }
398 
GetTemplateURLForKeyword(const base::string16 & keyword) const399 const TemplateURL* TemplateURLService::GetTemplateURLForKeyword(
400     const base::string16& keyword) const {
401   // Finds and returns the best match for |keyword|.
402   const auto match_range = keyword_to_turl_and_length_.equal_range(keyword);
403   if (match_range.first != match_range.second) {
404     // Among the matches for |keyword| in the multimap, return the best one.
405     return std::min_element(
406                match_range.first, match_range.second,
407                [](const auto& a, const auto& b) {
408                  return a.second.first
409                      ->IsBetterThanEngineWithConflictingKeyword(b.second.first);
410                })
411         ->second.first;
412   }
413 
414   return (!loaded_ && initial_default_search_provider_ &&
415           (initial_default_search_provider_->keyword() == keyword))
416              ? initial_default_search_provider_.get()
417              : nullptr;
418 }
419 
GetTemplateURLForGUID(const std::string & sync_guid)420 TemplateURL* TemplateURLService::GetTemplateURLForGUID(
421     const std::string& sync_guid) {
422 return const_cast<TemplateURL*>(
423       static_cast<const TemplateURLService*>(this)->
424           GetTemplateURLForGUID(sync_guid));
425 }
426 
GetTemplateURLForGUID(const std::string & sync_guid) const427 const TemplateURL* TemplateURLService::GetTemplateURLForGUID(
428     const std::string& sync_guid) const {
429   auto elem(guid_to_turl_.find(sync_guid));
430   if (elem != guid_to_turl_.end())
431     return elem->second;
432   return (!loaded_ && initial_default_search_provider_ &&
433           (initial_default_search_provider_->sync_guid() == sync_guid))
434              ? initial_default_search_provider_.get()
435              : nullptr;
436 }
437 
GetTemplateURLForHost(const std::string & host)438 TemplateURL* TemplateURLService::GetTemplateURLForHost(
439     const std::string& host) {
440   return const_cast<TemplateURL*>(
441       static_cast<const TemplateURLService*>(this)->
442           GetTemplateURLForHost(host));
443 }
444 
GetTemplateURLForHost(const std::string & host) const445 const TemplateURL* TemplateURLService::GetTemplateURLForHost(
446     const std::string& host) const {
447   if (loaded_)
448     return provider_map_->GetTemplateURLForHost(host);
449   TemplateURL* initial_dsp = initial_default_search_provider_.get();
450   return (initial_dsp &&
451           (initial_dsp->GenerateSearchURL(search_terms_data()).host_piece() ==
452            host))
453              ? initial_dsp
454              : nullptr;
455 }
456 
Add(std::unique_ptr<TemplateURL> template_url)457 TemplateURL* TemplateURLService::Add(
458     std::unique_ptr<TemplateURL> template_url) {
459   DCHECK(template_url);
460   DCHECK(
461       !IsCreatedByExtension(template_url.get()) ||
462       (!FindTemplateURLForExtension(template_url->extension_info_->extension_id,
463                                     template_url->type()) &&
464        template_url->id() == kInvalidTemplateURLID));
465 
466   return Add(std::move(template_url), true);
467 }
468 
AddWithOverrides(std::unique_ptr<TemplateURL> template_url,const base::string16 & short_name,const base::string16 & keyword,const std::string & url)469 TemplateURL* TemplateURLService::AddWithOverrides(
470     std::unique_ptr<TemplateURL> template_url,
471     const base::string16& short_name,
472     const base::string16& keyword,
473     const std::string& url) {
474   DCHECK(!short_name.empty());
475   DCHECK(!keyword.empty());
476   DCHECK(!url.empty());
477   template_url->data_.SetShortName(short_name);
478   template_url->data_.SetKeyword(keyword);
479   template_url->SetURL(url);
480   return Add(std::move(template_url));
481 }
482 
Remove(const TemplateURL * template_url)483 void TemplateURLService::Remove(const TemplateURL* template_url) {
484   DCHECK_NE(template_url, default_search_provider_);
485 
486   auto i = FindTemplateURL(&template_urls_, template_url);
487   if (i == template_urls_.end())
488     return;
489 
490   Scoper scoper(this);
491   model_mutated_notification_pending_ = true;
492 
493   RemoveFromMaps(template_url);
494 
495   // Remove it from the vector containing all TemplateURLs.
496   std::unique_ptr<TemplateURL> scoped_turl = std::move(*i);
497   template_urls_.erase(i);
498 
499   if (template_url->type() == TemplateURL::NORMAL) {
500     if (web_data_service_)
501       web_data_service_->RemoveKeyword(template_url->id());
502 
503     // Inform sync of the deletion.
504     ProcessTemplateURLChange(FROM_HERE, template_url,
505                              syncer::SyncChange::ACTION_DELETE);
506 
507     // The default search engine can't be deleted. But the user defined DSE can
508     // be hidden by an extension or policy and then deleted. Clean up the user
509     // prefs then.
510     if (prefs_ &&
511         (template_url->sync_guid() ==
512          prefs_->GetString(prefs::kSyncedDefaultSearchProviderGUID))) {
513       prefs_->SetString(prefs::kSyncedDefaultSearchProviderGUID, std::string());
514     }
515 
516     UMA_HISTOGRAM_ENUMERATION(kDeleteSyncedEngineHistogramName,
517                               DELETE_ENGINE_USER_ACTION, DELETE_ENGINE_MAX);
518   }
519 
520   if (loaded_ && client_)
521     client_->DeleteAllSearchTermsForKeyword(template_url->id());
522 }
523 
RemoveExtensionControlledTURL(const std::string & extension_id,TemplateURL::Type type)524 void TemplateURLService::RemoveExtensionControlledTURL(
525     const std::string& extension_id,
526     TemplateURL::Type type) {
527   TemplateURL* url = FindTemplateURLForExtension(extension_id, type);
528   if (!url)
529     return;
530   // NULL this out so that we can call Remove.
531   if (default_search_provider_ == url)
532     default_search_provider_ = nullptr;
533   Remove(url);
534 }
535 
RemoveAutoGeneratedSince(base::Time created_after)536 void TemplateURLService::RemoveAutoGeneratedSince(base::Time created_after) {
537   RemoveAutoGeneratedBetween(created_after, base::Time());
538 }
539 
RemoveAutoGeneratedBetween(base::Time created_after,base::Time created_before)540 void TemplateURLService::RemoveAutoGeneratedBetween(base::Time created_after,
541                                                     base::Time created_before) {
542   RemoveAutoGeneratedForUrlsBetween(base::Callback<bool(const GURL&)>(),
543                                     created_after, created_before);
544 }
545 
RemoveAutoGeneratedForUrlsBetween(const base::Callback<bool (const GURL &)> & url_filter,base::Time created_after,base::Time created_before)546 void TemplateURLService::RemoveAutoGeneratedForUrlsBetween(
547     const base::Callback<bool(const GURL&)>& url_filter,
548     base::Time created_after,
549     base::Time created_before) {
550   Scoper scoper(this);
551 
552   for (size_t i = 0; i < template_urls_.size();) {
553     if (template_urls_[i]->date_created() >= created_after &&
554         (created_before.is_null() ||
555          template_urls_[i]->date_created() < created_before) &&
556         CanReplace(template_urls_[i].get()) &&
557         (url_filter.is_null() ||
558          url_filter.Run(
559              template_urls_[i]->GenerateSearchURL(search_terms_data())))) {
560       Remove(template_urls_[i].get());
561     } else {
562       ++i;
563     }
564   }
565 }
566 
RegisterOmniboxKeyword(const std::string & extension_id,const std::string & extension_name,const std::string & keyword,const std::string & template_url_string,const base::Time & extension_install_time)567 void TemplateURLService::RegisterOmniboxKeyword(
568     const std::string& extension_id,
569     const std::string& extension_name,
570     const std::string& keyword,
571     const std::string& template_url_string,
572     const base::Time& extension_install_time) {
573   DCHECK(loaded_);
574 
575   if (FindTemplateURLForExtension(extension_id,
576                                   TemplateURL::OMNIBOX_API_EXTENSION))
577     return;
578 
579   TemplateURLData data;
580   data.SetShortName(base::UTF8ToUTF16(extension_name));
581   data.SetKeyword(base::UTF8ToUTF16(keyword));
582   data.SetURL(template_url_string);
583   Add(std::make_unique<TemplateURL>(data, TemplateURL::OMNIBOX_API_EXTENSION,
584                                     extension_id, extension_install_time,
585                                     false));
586 }
587 
GetTemplateURLs()588 TemplateURLService::TemplateURLVector TemplateURLService::GetTemplateURLs() {
589   TemplateURLVector result;
590   for (const auto& turl : template_urls_)
591     result.push_back(turl.get());
592   return result;
593 }
594 
IncrementUsageCount(TemplateURL * url)595 void TemplateURLService::IncrementUsageCount(TemplateURL* url) {
596   DCHECK(url);
597   // Extension-controlled search engines are not persisted.
598   if (url->type() != TemplateURL::NORMAL)
599     return;
600   if (!Contains(&template_urls_, url))
601     return;
602   ++url->data_.usage_count;
603 
604   if (web_data_service_)
605     web_data_service_->UpdateKeyword(url->data());
606 }
607 
ResetTemplateURL(TemplateURL * url,const base::string16 & title,const base::string16 & keyword,const std::string & search_url)608 void TemplateURLService::ResetTemplateURL(TemplateURL* url,
609                                           const base::string16& title,
610                                           const base::string16& keyword,
611                                           const std::string& search_url) {
612   DCHECK(!IsCreatedByExtension(url));
613   DCHECK(!keyword.empty());
614   DCHECK(!search_url.empty());
615   TemplateURLData data(url->data());
616   data.SetShortName(title);
617   data.SetKeyword(keyword);
618   if (search_url != data.url()) {
619     data.SetURL(search_url);
620     // The urls have changed, reset the favicon url.
621     data.favicon_url = GURL();
622   }
623   data.safe_for_autoreplace = false;
624   data.last_modified = clock_->Now();
625   Update(url, TemplateURL(data));
626 }
627 
CreateOrUpdateTemplateURLFromPlayAPIData(const base::string16 & title,const base::string16 & keyword,const std::string & search_url,const std::string & suggestions_url,const std::string & favicon_url)628 TemplateURL* TemplateURLService::CreateOrUpdateTemplateURLFromPlayAPIData(
629     const base::string16& title,
630     const base::string16& keyword,
631     const std::string& search_url,
632     const std::string& suggestions_url,
633     const std::string& favicon_url) {
634   TemplateURL* existing_turl = FindNonExtensionTemplateURLForKeyword(keyword);
635   TemplateURLData data;
636   if (existing_turl)
637     data = existing_turl->data();
638   data.SetShortName(title);
639   data.SetKeyword(keyword);
640   data.SetURL(search_url);
641   data.suggestions_url = suggestions_url;
642   data.favicon_url = GURL(favicon_url);
643   data.safe_for_autoreplace = true;
644   data.created_from_play_api = true;
645   if (existing_turl) {
646     Update(existing_turl, TemplateURL(data));
647   } else {
648     existing_turl = Add(std::make_unique<TemplateURL>(data));
649     DCHECK(existing_turl);
650   }
651   return existing_turl;
652 }
653 
UpdateProviderFavicons(const GURL & potential_search_url,const GURL & favicon_url)654 void TemplateURLService::UpdateProviderFavicons(
655     const GURL& potential_search_url,
656     const GURL& favicon_url) {
657   DCHECK(loaded_);
658   DCHECK(potential_search_url.is_valid());
659 
660   const TemplateURLSet* urls_for_host =
661       provider_map_->GetURLsForHost(potential_search_url.host());
662   if (!urls_for_host)
663     return;
664 
665   // Make a copy of the container of the matching TemplateURLs, as the original
666   // container is invalidated as we update the contained TemplateURLs.
667   TemplateURLSet urls_for_host_copy(*urls_for_host);
668 
669   Scoper scoper(this);
670   for (TemplateURL* turl : urls_for_host_copy) {
671     if (!IsCreatedByExtension(turl) &&
672         turl->IsSearchURL(potential_search_url, search_terms_data()) &&
673         turl->favicon_url() != favicon_url) {
674       TemplateURLData data(turl->data());
675       data.favicon_url = favicon_url;
676       Update(turl, TemplateURL(data));
677     }
678   }
679 }
680 
CanMakeDefault(const TemplateURL * url) const681 bool TemplateURLService::CanMakeDefault(const TemplateURL* url) const {
682   return
683       ((default_search_provider_source_ == DefaultSearchManager::FROM_USER) ||
684        (default_search_provider_source_ ==
685         DefaultSearchManager::FROM_FALLBACK)) &&
686       (url != GetDefaultSearchProvider()) &&
687       url->url_ref().SupportsReplacement(search_terms_data()) &&
688       (url->type() == TemplateURL::NORMAL);
689 }
690 
SetUserSelectedDefaultSearchProvider(TemplateURL * url)691 void TemplateURLService::SetUserSelectedDefaultSearchProvider(
692     TemplateURL* url) {
693   // Omnibox keywords cannot be made default. Extension-controlled search
694   // engines can be made default only by the extension itself because they
695   // aren't persisted.
696   DCHECK(!url || !IsCreatedByExtension(url));
697   if (load_failed_) {
698     // Skip the DefaultSearchManager, which will persist to user preferences.
699     if ((default_search_provider_source_ == DefaultSearchManager::FROM_USER) ||
700         (default_search_provider_source_ ==
701          DefaultSearchManager::FROM_FALLBACK)) {
702       ApplyDefaultSearchChange(url ? &url->data() : nullptr,
703                                DefaultSearchManager::FROM_USER);
704     }
705   } else {
706     // We rely on the DefaultSearchManager to call ApplyDefaultSearchChange if,
707     // in fact, the effective DSE changes.
708     if (url)
709       default_search_manager_.SetUserSelectedDefaultSearchEngine(url->data());
710     else
711       default_search_manager_.ClearUserSelectedDefaultSearchEngine();
712   }
713 }
714 
GetDefaultSearchProvider() const715 const TemplateURL* TemplateURLService::GetDefaultSearchProvider() const {
716   return loaded_ ? default_search_provider_
717                  : initial_default_search_provider_.get();
718 }
719 
720 const TemplateURL*
GetDefaultSearchProviderIgnoringExtensions() const721 TemplateURLService::GetDefaultSearchProviderIgnoringExtensions() const {
722   std::unique_ptr<TemplateURLData> next_search =
723       default_search_manager_.GetDefaultSearchEngineIgnoringExtensions();
724   if (!next_search)
725     return nullptr;
726 
727   // Find the TemplateURL matching the data retrieved.
728   auto iter = std::find_if(template_urls_.begin(), template_urls_.end(),
729                            [this, &next_search](const auto& turl_to_check) {
730                              return TemplateURL::MatchesData(
731                                  turl_to_check.get(), next_search.get(),
732                                  search_terms_data());
733                            });
734   return iter == template_urls_.end() ? nullptr : iter->get();
735 }
736 
IsSearchResultsPageFromDefaultSearchProvider(const GURL & url) const737 bool TemplateURLService::IsSearchResultsPageFromDefaultSearchProvider(
738     const GURL& url) const {
739   const TemplateURL* default_provider = GetDefaultSearchProvider();
740   return default_provider &&
741       default_provider->IsSearchURL(url, search_terms_data());
742 }
743 
IsExtensionControlledDefaultSearch() const744 bool TemplateURLService::IsExtensionControlledDefaultSearch() const {
745   return default_search_provider_source_ ==
746       DefaultSearchManager::FROM_EXTENSION;
747 }
748 
RepairPrepopulatedSearchEngines()749 void TemplateURLService::RepairPrepopulatedSearchEngines() {
750   // Can't clean DB if it hasn't been loaded.
751   DCHECK(loaded());
752 
753   Scoper scoper(this);
754 
755   if ((default_search_provider_source_ == DefaultSearchManager::FROM_USER) ||
756       (default_search_provider_source_ ==
757           DefaultSearchManager::FROM_FALLBACK)) {
758     // Clear |default_search_provider_| in case we want to remove the engine it
759     // points to. This will get reset at the end of the function anyway.
760     default_search_provider_ = nullptr;
761   }
762 
763   std::vector<std::unique_ptr<TemplateURLData>> prepopulated_urls =
764       TemplateURLPrepopulateData::GetPrepopulatedEngines(prefs_, nullptr);
765   DCHECK(!prepopulated_urls.empty());
766   ActionsFromPrepopulateData actions(CreateActionsFromCurrentPrepopulateData(
767       &prepopulated_urls, template_urls_, default_search_provider_));
768 
769   // Remove items.
770   for (auto i = actions.removed_engines.begin();
771        i < actions.removed_engines.end(); ++i)
772     Remove(*i);
773 
774   // Edit items.
775   for (auto i(actions.edited_engines.begin()); i < actions.edited_engines.end();
776        ++i) {
777     TemplateURL new_values(i->second);
778     Update(i->first, new_values);
779   }
780 
781   // Add items.
782   for (std::vector<TemplateURLData>::const_iterator i =
783            actions.added_engines.begin();
784        i < actions.added_engines.end();
785        ++i) {
786     Add(std::make_unique<TemplateURL>(*i));
787   }
788 
789   base::AutoReset<DefaultSearchChangeOrigin> change_origin(
790       &dsp_change_origin_, DSP_CHANGE_PROFILE_RESET);
791 
792   default_search_manager_.ClearUserSelectedDefaultSearchEngine();
793 
794   if (default_search_provider_) {
795     // Set fallback engine as user selected, because repair is considered a user
796     // action and we are expected to sync new fallback engine to other devices.
797     const TemplateURLData* fallback_engine_data =
798         default_search_manager_.GetFallbackSearchEngine();
799     if (fallback_engine_data) {
800       TemplateURL* fallback_engine =
801           FindPrepopulatedTemplateURL(fallback_engine_data->prepopulate_id);
802       // The fallback engine is created from built-in/override data that should
803       // always have a prepopulate ID, so this engine should always exist after
804       // a repair.
805       DCHECK(fallback_engine);
806       // Write the fallback engine's GUID to prefs, which will cause
807       // OnSyncedDefaultSearchProviderGUIDChanged() to set it as the new
808       // user-selected engine.
809       prefs_->SetString(prefs::kSyncedDefaultSearchProviderGUID,
810                         fallback_engine->sync_guid());
811     }
812   } else {
813     // If the default search provider came from a user pref we would have been
814     // notified of the new (fallback-provided) value in
815     // ClearUserSelectedDefaultSearchEngine() above. Since we are here, the
816     // value was presumably originally a fallback value (which may have been
817     // repaired).
818     DefaultSearchManager::Source source;
819     const TemplateURLData* new_dse =
820         default_search_manager_.GetDefaultSearchEngine(&source);
821     ApplyDefaultSearchChange(new_dse, source);
822   }
823 }
824 
AddObserver(TemplateURLServiceObserver * observer)825 void TemplateURLService::AddObserver(TemplateURLServiceObserver* observer) {
826   model_observers_.AddObserver(observer);
827 }
828 
RemoveObserver(TemplateURLServiceObserver * observer)829 void TemplateURLService::RemoveObserver(TemplateURLServiceObserver* observer) {
830   model_observers_.RemoveObserver(observer);
831 }
832 
Load()833 void TemplateURLService::Load() {
834   if (loaded_ || load_handle_ || disable_load_)
835     return;
836 
837   if (web_data_service_)
838     load_handle_ = web_data_service_->GetKeywords(this);
839   else
840     ChangeToLoadedState();
841 }
842 
843 std::unique_ptr<TemplateURLService::Subscription>
RegisterOnLoadedCallback(const base::RepeatingClosure & callback)844 TemplateURLService::RegisterOnLoadedCallback(
845     const base::RepeatingClosure& callback) {
846   return loaded_ ? std::unique_ptr<TemplateURLService::Subscription>()
847                  : on_loaded_callbacks_.Add(callback);
848 }
849 
OnWebDataServiceRequestDone(KeywordWebDataService::Handle h,std::unique_ptr<WDTypedResult> result)850 void TemplateURLService::OnWebDataServiceRequestDone(
851     KeywordWebDataService::Handle h,
852     std::unique_ptr<WDTypedResult> result) {
853   // Reset the load_handle so that we don't try and cancel the load in
854   // the destructor.
855   load_handle_ = 0;
856 
857   if (!result) {
858     // Results are null if the database went away or (most likely) wasn't
859     // loaded.
860     load_failed_ = true;
861     web_data_service_ = nullptr;
862     ChangeToLoadedState();
863     return;
864   }
865 
866   std::unique_ptr<OwnedTemplateURLVector> template_urls =
867       std::make_unique<OwnedTemplateURLVector>();
868   int new_resource_keyword_version = 0;
869   {
870     GetSearchProvidersUsingKeywordResult(
871         *result, web_data_service_.get(), prefs_, template_urls.get(),
872         (default_search_provider_source_ == DefaultSearchManager::FROM_USER)
873             ? initial_default_search_provider_.get()
874             : nullptr,
875         search_terms_data(), &new_resource_keyword_version, &pre_sync_deletes_);
876   }
877 
878   Scoper scoper(this);
879 
880   {
881     PatchMissingSyncGUIDs(template_urls.get());
882     SetTemplateURLs(std::move(template_urls));
883 
884     // This initializes provider_map_ which should be done before
885     // calling UpdateKeywordSearchTermsForURL.
886     ChangeToLoadedState();
887 
888     // Index any visits that occurred before we finished loading.
889     for (size_t i = 0; i < visits_to_add_.size(); ++i)
890       UpdateKeywordSearchTermsForURL(visits_to_add_[i]);
891     visits_to_add_.clear();
892 
893     if (new_resource_keyword_version)
894       web_data_service_->SetBuiltinKeywordVersion(new_resource_keyword_version);
895   }
896 
897   if (default_search_provider_) {
898     UMA_HISTOGRAM_ENUMERATION(
899         "Search.DefaultSearchProviderType",
900         default_search_provider_->GetEngineType(search_terms_data()),
901         SEARCH_ENGINE_MAX);
902   }
903 }
904 
GetKeywordShortName(const base::string16 & keyword,bool * is_omnibox_api_extension_keyword) const905 base::string16 TemplateURLService::GetKeywordShortName(
906     const base::string16& keyword,
907     bool* is_omnibox_api_extension_keyword) const {
908   const TemplateURL* template_url = GetTemplateURLForKeyword(keyword);
909 
910   // TODO(sky): Once LocationBarView adds a listener to the TemplateURLService
911   // to track changes to the model, this should become a DCHECK.
912   if (template_url) {
913     *is_omnibox_api_extension_keyword =
914         template_url->type() == TemplateURL::OMNIBOX_API_EXTENSION;
915     return template_url->AdjustedShortNameForLocaleDirection();
916   }
917   *is_omnibox_api_extension_keyword = false;
918   return base::string16();
919 }
920 
OnHistoryURLVisited(const URLVisitedDetails & details)921 void TemplateURLService::OnHistoryURLVisited(const URLVisitedDetails& details) {
922   if (!loaded_)
923     visits_to_add_.push_back(details);
924   else
925     UpdateKeywordSearchTermsForURL(details);
926 }
927 
Shutdown()928 void TemplateURLService::Shutdown() {
929   for (auto& observer : model_observers_)
930     observer.OnTemplateURLServiceShuttingDown();
931 
932   if (client_)
933     client_->Shutdown();
934   // This check has to be done at Shutdown() instead of in the dtor to ensure
935   // that no clients of KeywordWebDataService are holding ptrs to it after the
936   // first phase of the KeyedService Shutdown() process.
937   if (load_handle_) {
938     DCHECK(web_data_service_);
939     web_data_service_->CancelRequest(load_handle_);
940   }
941   web_data_service_ = nullptr;
942 }
943 
WaitUntilReadyToSync(base::OnceClosure done)944 void TemplateURLService::WaitUntilReadyToSync(base::OnceClosure done) {
945   DCHECK(!on_loaded_callback_for_sync_);
946 
947   // We force a load here to allow remote updates to be processed, without
948   // waiting for the lazy load.
949   Load();
950 
951   if (loaded_)
952     std::move(done).Run();
953   else
954     on_loaded_callback_for_sync_ = std::move(done);
955 }
956 
GetAllSyncData(syncer::ModelType type) const957 syncer::SyncDataList TemplateURLService::GetAllSyncData(
958     syncer::ModelType type) const {
959   DCHECK_EQ(syncer::SEARCH_ENGINES, type);
960 
961   syncer::SyncDataList current_data;
962   for (const auto& turl : template_urls_) {
963     // We don't sync keywords managed by policy.
964     if (turl->created_by_policy())
965       continue;
966     // We don't sync extension-controlled search engines.
967     if (turl->type() != TemplateURL::NORMAL)
968       continue;
969     current_data.push_back(CreateSyncDataFromTemplateURL(*turl));
970   }
971 
972   return current_data;
973 }
974 
ProcessSyncChanges(const base::Location & from_here,const syncer::SyncChangeList & change_list)975 base::Optional<syncer::ModelError> TemplateURLService::ProcessSyncChanges(
976     const base::Location& from_here,
977     const syncer::SyncChangeList& change_list) {
978   if (!models_associated_) {
979     return syncer::ModelError(FROM_HERE, "Models not yet associated.");
980   }
981   DCHECK(loaded_);
982 
983   base::AutoReset<bool> processing_changes(&processing_syncer_changes_, true);
984 
985   Scoper scoper(this);
986 
987   // We've started syncing, so set our origin member to the base Sync value.
988   // As we move through Sync Code, we may set this to increasingly specific
989   // origins so we can tell what exactly caused a DSP change.
990   base::AutoReset<DefaultSearchChangeOrigin> change_origin(&dsp_change_origin_,
991       DSP_CHANGE_SYNC_UNINTENTIONAL);
992 
993   syncer::SyncChangeList new_changes;
994   syncer::SyncError error;
995   for (auto iter = change_list.begin(); iter != change_list.end(); ++iter) {
996     DCHECK_EQ(syncer::SEARCH_ENGINES, iter->sync_data().GetDataType());
997 
998     TemplateURL* existing_turl = GetTemplateURLForGUID(
999         iter->sync_data().GetSpecifics().search_engine().sync_guid());
1000     std::unique_ptr<TemplateURL> turl =
1001         CreateTemplateURLFromTemplateURLAndSyncData(
1002             client_.get(), prefs_, search_terms_data(), existing_turl,
1003             iter->sync_data(), &new_changes);
1004     if (!turl)
1005       continue;
1006 
1007     const std::string error_msg =
1008         "ProcessSyncChanges failed on ChangeType " +
1009         syncer::SyncChange::ChangeTypeToString(iter->change_type());
1010     if (iter->change_type() == syncer::SyncChange::ACTION_INVALID) {
1011       error = sync_error_factory_->CreateAndUploadError(FROM_HERE, error_msg);
1012       continue;
1013     }
1014 
1015     if (iter->change_type() == syncer::SyncChange::ACTION_DELETE) {
1016       if (!existing_turl) {
1017         // Can't DELETE a non-existent engine, although we log it.
1018         UMA_HISTOGRAM_ENUMERATION(kSearchTemplateURLEventsHistogramName,
1019                                   SYNC_DELETE_FAIL_NONEXISTENT_ENGINE,
1020                                   SEARCH_TEMPLATE_URL_EVENT_MAX);
1021         error = sync_error_factory_->CreateAndUploadError(FROM_HERE, error_msg);
1022         continue;
1023       }
1024 
1025       // We can get an ACTION_DELETE for the default search provider if the user
1026       // has changed the default search provider on a different machine, and we
1027       // get the search engine update before the preference update.
1028       //
1029       // In this case, ignore the delete, because we never want to reset the
1030       // default search provider as a result of ACTION_DELETE. If the preference
1031       // update arrives later, we may be stuck with an extra search engine entry
1032       // in this edge case, but it's better than most alternatives.
1033       //
1034       // In the past, we tried re-creating the deleted TemplateURL, but it was
1035       // likely a source of duplicate search engine entries. crbug.com/1022775
1036       if (existing_turl != GetDefaultSearchProvider()) {
1037         Remove(existing_turl);
1038         UMA_HISTOGRAM_ENUMERATION(kSearchTemplateURLEventsHistogramName,
1039                                   SYNC_DELETE_SUCCESS,
1040                                   SEARCH_TEMPLATE_URL_EVENT_MAX);
1041       } else {
1042         UMA_HISTOGRAM_ENUMERATION(kSearchTemplateURLEventsHistogramName,
1043                                   SYNC_DELETE_FAIL_DEFAULT_SEARCH_PROVIDER,
1044                                   SEARCH_TEMPLATE_URL_EVENT_MAX);
1045       }
1046       continue;
1047     }
1048 
1049     if ((iter->change_type() == syncer::SyncChange::ACTION_ADD &&
1050          existing_turl) ||
1051         (iter->change_type() == syncer::SyncChange::ACTION_UPDATE &&
1052          !existing_turl)) {
1053       // Can't ADD an already-existing engine, and can't UPDATE a non-existent
1054       // engine. Early exit here to avoid ResolvingSyncKeywordConflict().
1055       error = sync_error_factory_->CreateAndUploadError(FROM_HERE, error_msg);
1056       continue;
1057     }
1058 
1059     // Explicitly don't check for conflicts against extension keywords; in this
1060     // case the functions which modify the keyword map know how to handle the
1061     // conflicts.
1062     // TODO(mpcomplete): If we allow editing extension keywords, then those will
1063     // need to undergo conflict resolution.
1064     TemplateURL* existing_keyword_turl =
1065         FindNonExtensionTemplateURLForKeyword(turl->keyword());
1066     const bool has_conflict =
1067         existing_keyword_turl && (existing_keyword_turl != existing_turl);
1068     if (has_conflict) {
1069       // Resolve any conflicts with other entries so we can safely update the
1070       // keyword.
1071       ResolveSyncKeywordConflict(turl.get(), existing_keyword_turl,
1072                                  &new_changes);
1073     }
1074 
1075     if (iter->change_type() == syncer::SyncChange::ACTION_ADD) {
1076       base::AutoReset<DefaultSearchChangeOrigin> change_origin(
1077           &dsp_change_origin_, DSP_CHANGE_SYNC_ADD);
1078       // Force the local ID to kInvalidTemplateURLID so we can add it.
1079       TemplateURLData data(turl->data());
1080       data.id = kInvalidTemplateURLID;
1081       auto added_ptr = std::make_unique<TemplateURL>(data);
1082       TemplateURL* added = added_ptr.get();
1083       if (Add(std::move(added_ptr)))
1084         MaybeUpdateDSEViaPrefs(added);
1085       continue;
1086     }
1087 
1088     DCHECK_EQ(syncer::SyncChange::ACTION_UPDATE, iter->change_type());
1089     if (Update(existing_turl, *turl))
1090       MaybeUpdateDSEViaPrefs(existing_turl);
1091   }
1092 
1093   // If something went wrong, we want to prematurely exit to avoid pushing
1094   // inconsistent data to Sync. We return the last error we received.
1095   if (error.IsSet())
1096     return ConvertToModelError(error);
1097 
1098   return sync_processor_->ProcessSyncChanges(from_here, new_changes);
1099 }
1100 
MergeDataAndStartSyncing(syncer::ModelType type,const syncer::SyncDataList & initial_sync_data,std::unique_ptr<syncer::SyncChangeProcessor> sync_processor,std::unique_ptr<syncer::SyncErrorFactory> sync_error_factory)1101 base::Optional<syncer::ModelError> TemplateURLService::MergeDataAndStartSyncing(
1102     syncer::ModelType type,
1103     const syncer::SyncDataList& initial_sync_data,
1104     std::unique_ptr<syncer::SyncChangeProcessor> sync_processor,
1105     std::unique_ptr<syncer::SyncErrorFactory> sync_error_factory) {
1106   DCHECK(loaded_);
1107   DCHECK_EQ(type, syncer::SEARCH_ENGINES);
1108   DCHECK(!sync_processor_);
1109   DCHECK(sync_processor);
1110   DCHECK(sync_error_factory);
1111 
1112   // Disable sync if we failed to load.
1113   if (load_failed_) {
1114     return syncer::ModelError(FROM_HERE, "Local database load failed.");
1115   }
1116 
1117   sync_processor_ = std::move(sync_processor);
1118   sync_error_factory_ = std::move(sync_error_factory);
1119 
1120   // We do a lot of calls to Add/Remove/ResetTemplateURL here, so ensure we
1121   // don't step on our own toes.
1122   base::AutoReset<bool> processing_changes(&processing_syncer_changes_, true);
1123 
1124   Scoper scoper(this);
1125 
1126   // We've started syncing, so set our origin member to the base Sync value.
1127   // As we move through Sync Code, we may set this to increasingly specific
1128   // origins so we can tell what exactly caused a DSP change.
1129   base::AutoReset<DefaultSearchChangeOrigin> change_origin(&dsp_change_origin_,
1130       DSP_CHANGE_SYNC_UNINTENTIONAL);
1131 
1132   syncer::SyncChangeList new_changes;
1133 
1134   // Build maps of our sync GUIDs to syncer::SyncData.
1135   SyncDataMap local_data_map = CreateGUIDToSyncDataMap(
1136       GetAllSyncData(syncer::SEARCH_ENGINES));
1137   SyncDataMap sync_data_map = CreateGUIDToSyncDataMap(initial_sync_data);
1138 
1139   for (SyncDataMap::const_iterator iter = sync_data_map.begin();
1140       iter != sync_data_map.end(); ++iter) {
1141     TemplateURL* local_turl = GetTemplateURLForGUID(iter->first);
1142     std::unique_ptr<TemplateURL> sync_turl(
1143         CreateTemplateURLFromTemplateURLAndSyncData(
1144             client_.get(), prefs_, search_terms_data(), local_turl,
1145             iter->second, &new_changes));
1146     if (!sync_turl)
1147       continue;
1148 
1149     if (pre_sync_deletes_.find(sync_turl->sync_guid()) !=
1150         pre_sync_deletes_.end()) {
1151       // This entry was deleted before the initial sync began (possibly through
1152       // preprocessing in TemplateURLService's loading code). Ignore it and send
1153       // an ACTION_DELETE up to the server.
1154       new_changes.push_back(
1155           syncer::SyncChange(FROM_HERE,
1156                              syncer::SyncChange::ACTION_DELETE,
1157                              iter->second));
1158       UMA_HISTOGRAM_ENUMERATION(kDeleteSyncedEngineHistogramName,
1159           DELETE_ENGINE_PRE_SYNC, DELETE_ENGINE_MAX);
1160       continue;
1161     }
1162 
1163     if (local_turl) {
1164       DCHECK(IsFromSync(local_turl, sync_data_map));
1165       // This local search engine is already synced. If the timestamp differs
1166       // from Sync, we need to update locally or to the cloud. Note that if the
1167       // timestamps are equal, we touch neither.
1168       if (sync_turl->last_modified() > local_turl->last_modified()) {
1169         // We've received an update from Sync. We should replace all synced
1170         // fields in the local TemplateURL. Note that this includes the
1171         // TemplateURLID and the TemplateURL may have to be reparsed. This
1172         // also makes the local data's last_modified timestamp equal to Sync's,
1173         // avoiding an Update on the next MergeData call.
1174         Update(local_turl, *sync_turl);
1175       } else if (sync_turl->last_modified() < local_turl->last_modified()) {
1176         // Otherwise, we know we have newer data, so update Sync with our
1177         // data fields.
1178         new_changes.push_back(
1179             syncer::SyncChange(FROM_HERE,
1180                                syncer::SyncChange::ACTION_UPDATE,
1181                                local_data_map[local_turl->sync_guid()]));
1182       }
1183       local_data_map.erase(iter->first);
1184     } else {
1185       // The search engine from the cloud has not been synced locally. Merge it
1186       // into our local model. This will handle any conflicts with local (and
1187       // already-synced) TemplateURLs. It will prefer to keep entries from Sync
1188       // over not-yet-synced TemplateURLs.
1189       MergeInSyncTemplateURL(sync_turl.get(), sync_data_map, &new_changes,
1190                              &local_data_map);
1191     }
1192   }
1193 
1194 
1195   // The remaining SyncData in local_data_map should be everything that needs to
1196   // be pushed as ADDs to sync.
1197   for (SyncDataMap::const_iterator iter = local_data_map.begin();
1198       iter != local_data_map.end(); ++iter) {
1199     new_changes.push_back(
1200         syncer::SyncChange(FROM_HERE,
1201                            syncer::SyncChange::ACTION_ADD,
1202                            iter->second));
1203   }
1204 
1205   // Do some post-processing on the change list to ensure that we are sending
1206   // valid changes to sync_processor_.
1207   PruneSyncChanges(&sync_data_map, &new_changes);
1208 
1209   LogDuplicatesHistogram(GetTemplateURLs());
1210   base::Optional<syncer::ModelError> error =
1211       sync_processor_->ProcessSyncChanges(FROM_HERE, new_changes);
1212   if (!error.has_value()) {
1213     // The ACTION_DELETEs from this set are processed. Empty it so we don't try
1214     // to reuse them on the next call to MergeDataAndStartSyncing.
1215     pre_sync_deletes_.clear();
1216 
1217     models_associated_ = true;
1218   }
1219 
1220   return error;
1221 }
1222 
StopSyncing(syncer::ModelType type)1223 void TemplateURLService::StopSyncing(syncer::ModelType type) {
1224   DCHECK_EQ(type, syncer::SEARCH_ENGINES);
1225   models_associated_ = false;
1226   sync_processor_.reset();
1227   sync_error_factory_.reset();
1228 }
1229 
ProcessTemplateURLChange(const base::Location & from_here,const TemplateURL * turl,syncer::SyncChange::SyncChangeType type)1230 void TemplateURLService::ProcessTemplateURLChange(
1231     const base::Location& from_here,
1232     const TemplateURL* turl,
1233     syncer::SyncChange::SyncChangeType type) {
1234   DCHECK_NE(type, syncer::SyncChange::ACTION_INVALID);
1235   DCHECK(turl);
1236 
1237   if (!models_associated_)
1238     return;  // Not syncing.
1239 
1240   if (processing_syncer_changes_)
1241     return;  // These are changes originating from us. Ignore.
1242 
1243   // Avoid syncing keywords managed by policy.
1244   if (turl->created_by_policy())
1245     return;
1246 
1247   // Avoid syncing extension-controlled search engines.
1248   if (turl->type() == TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION)
1249     return;
1250 
1251   syncer::SyncData sync_data = CreateSyncDataFromTemplateURL(*turl);
1252   syncer::SyncChangeList changes = {
1253       syncer::SyncChange(from_here, type, sync_data)};
1254   sync_processor_->ProcessSyncChanges(FROM_HERE, changes);
1255 }
1256 
GetSessionToken()1257 std::string TemplateURLService::GetSessionToken() {
1258   base::TimeTicks current_time(base::TimeTicks::Now());
1259   // Renew token if it expired.
1260   if (current_time > token_expiration_time_) {
1261     const size_t kTokenBytes = 12;
1262     std::string raw_data;
1263     base::RandBytes(base::WriteInto(&raw_data, kTokenBytes + 1), kTokenBytes);
1264     base::Base64UrlEncode(raw_data,
1265                           base::Base64UrlEncodePolicy::INCLUDE_PADDING,
1266                           &current_token_);
1267   }
1268 
1269   // Extend expiration time another 60 seconds.
1270   token_expiration_time_ = current_time + base::TimeDelta::FromSeconds(60);
1271   return current_token_;
1272 }
1273 
ClearSessionToken()1274 void TemplateURLService::ClearSessionToken() {
1275   token_expiration_time_ = base::TimeTicks();
1276 }
1277 
1278 // static
CreateSyncDataFromTemplateURL(const TemplateURL & turl)1279 syncer::SyncData TemplateURLService::CreateSyncDataFromTemplateURL(
1280     const TemplateURL& turl) {
1281   sync_pb::EntitySpecifics specifics;
1282   sync_pb::SearchEngineSpecifics* se_specifics =
1283       specifics.mutable_search_engine();
1284   se_specifics->set_short_name(base::UTF16ToUTF8(turl.short_name()));
1285   se_specifics->set_keyword(base::UTF16ToUTF8(turl.keyword()));
1286   se_specifics->set_favicon_url(turl.favicon_url().spec());
1287   se_specifics->set_url(turl.url());
1288   se_specifics->set_safe_for_autoreplace(turl.safe_for_autoreplace());
1289   se_specifics->set_originating_url(turl.originating_url().spec());
1290   se_specifics->set_date_created(turl.date_created().ToInternalValue());
1291   se_specifics->set_input_encodings(
1292       base::JoinString(turl.input_encodings(), ";"));
1293   se_specifics->set_suggestions_url(turl.suggestions_url());
1294   se_specifics->set_prepopulate_id(turl.prepopulate_id());
1295   if (!turl.image_url().empty())
1296     se_specifics->set_image_url(turl.image_url());
1297   se_specifics->set_new_tab_url(turl.new_tab_url());
1298   if (!turl.search_url_post_params().empty())
1299     se_specifics->set_search_url_post_params(turl.search_url_post_params());
1300   if (!turl.suggestions_url_post_params().empty()) {
1301     se_specifics->set_suggestions_url_post_params(
1302         turl.suggestions_url_post_params());
1303   }
1304   if (!turl.image_url_post_params().empty())
1305     se_specifics->set_image_url_post_params(turl.image_url_post_params());
1306   se_specifics->set_last_modified(turl.last_modified().ToInternalValue());
1307   se_specifics->set_sync_guid(turl.sync_guid());
1308   for (size_t i = 0; i < turl.alternate_urls().size(); ++i)
1309     se_specifics->add_alternate_urls(turl.alternate_urls()[i]);
1310 
1311   return syncer::SyncData::CreateLocalData(se_specifics->sync_guid(),
1312                                            se_specifics->keyword(),
1313                                            specifics);
1314 }
1315 
1316 // static
1317 std::unique_ptr<TemplateURL>
CreateTemplateURLFromTemplateURLAndSyncData(TemplateURLServiceClient * client,PrefService * prefs,const SearchTermsData & search_terms_data,const TemplateURL * existing_turl,const syncer::SyncData & sync_data,syncer::SyncChangeList * change_list)1318 TemplateURLService::CreateTemplateURLFromTemplateURLAndSyncData(
1319     TemplateURLServiceClient* client,
1320     PrefService* prefs,
1321     const SearchTermsData& search_terms_data,
1322     const TemplateURL* existing_turl,
1323     const syncer::SyncData& sync_data,
1324     syncer::SyncChangeList* change_list) {
1325   DCHECK(change_list);
1326 
1327   sync_pb::SearchEngineSpecifics specifics =
1328       sync_data.GetSpecifics().search_engine();
1329 
1330   // Past bugs might have caused either of these fields to be empty.  Just
1331   // delete this data off the server.
1332   if (specifics.url().empty() || specifics.sync_guid().empty()) {
1333     change_list->push_back(
1334         syncer::SyncChange(FROM_HERE,
1335                            syncer::SyncChange::ACTION_DELETE,
1336                            sync_data));
1337     UMA_HISTOGRAM_ENUMERATION(kDeleteSyncedEngineHistogramName,
1338         DELETE_ENGINE_EMPTY_FIELD, DELETE_ENGINE_MAX);
1339     return nullptr;
1340   }
1341 
1342   TemplateURLData data(existing_turl ?
1343       existing_turl->data() : TemplateURLData());
1344   data.SetShortName(base::UTF8ToUTF16(specifics.short_name()));
1345   data.originating_url = GURL(specifics.originating_url());
1346   base::string16 keyword(base::UTF8ToUTF16(specifics.keyword()));
1347   // NOTE: Once this code has shipped in a couple of stable releases, we can
1348   // probably remove the migration portion, comment out the
1349   // "autogenerate_keyword" field entirely in the .proto file, and fold the
1350   // empty keyword case into the "delete data" block above.
1351   bool reset_keyword =
1352       specifics.autogenerate_keyword() || specifics.keyword().empty();
1353   if (reset_keyword)
1354     keyword = base::ASCIIToUTF16("dummy");  // Will be replaced below.
1355   DCHECK(!keyword.empty());
1356   data.SetKeyword(keyword);
1357   data.SetURL(specifics.url());
1358   data.suggestions_url = specifics.suggestions_url();
1359   data.image_url = specifics.image_url();
1360   data.new_tab_url = specifics.new_tab_url();
1361   data.search_url_post_params = specifics.search_url_post_params();
1362   data.suggestions_url_post_params = specifics.suggestions_url_post_params();
1363   data.image_url_post_params = specifics.image_url_post_params();
1364   data.favicon_url = GURL(specifics.favicon_url());
1365   data.safe_for_autoreplace = specifics.safe_for_autoreplace();
1366   data.input_encodings = base::SplitString(
1367       specifics.input_encodings(), ";",
1368       base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
1369   // If the server data has duplicate encodings, we'll want to push an update
1370   // below to correct it.  Note that we also fix this in
1371   // GetSearchProvidersUsingKeywordResult(), since otherwise we'd never correct
1372   // local problems for clients which have disabled search engine sync.
1373   bool deduped = DeDupeEncodings(&data.input_encodings);
1374   data.date_created = base::Time::FromInternalValue(specifics.date_created());
1375   data.last_modified = base::Time::FromInternalValue(specifics.last_modified());
1376   data.prepopulate_id = specifics.prepopulate_id();
1377   data.sync_guid = specifics.sync_guid();
1378   data.alternate_urls.clear();
1379   for (int i = 0; i < specifics.alternate_urls_size(); ++i)
1380     data.alternate_urls.push_back(specifics.alternate_urls(i));
1381 
1382   std::unique_ptr<TemplateURL> turl(new TemplateURL(data));
1383   // If this TemplateURL matches a built-in prepopulated template URL, it's
1384   // possible that sync is trying to modify fields that should not be touched.
1385   // Revert these fields to the built-in values.
1386   UpdateTemplateURLIfPrepopulated(turl.get(), prefs);
1387 
1388   DCHECK_EQ(TemplateURL::NORMAL, turl->type());
1389   if (reset_keyword || deduped) {
1390     if (reset_keyword)
1391       turl->ResetKeywordIfNecessary(search_terms_data, true);
1392     syncer::SyncData sync_data = CreateSyncDataFromTemplateURL(*turl);
1393     change_list->push_back(syncer::SyncChange(FROM_HERE,
1394                                               syncer::SyncChange::ACTION_UPDATE,
1395                                               sync_data));
1396   } else if (turl->IsGoogleSearchURLWithReplaceableKeyword(search_terms_data)) {
1397     if (!existing_turl) {
1398       // We're adding a new TemplateURL that uses the Google base URL, so set
1399       // its keyword appropriately for the local environment.
1400       turl->ResetKeywordIfNecessary(search_terms_data, false);
1401     } else if (existing_turl->IsGoogleSearchURLWithReplaceableKeyword(
1402         search_terms_data)) {
1403       // Ignore keyword changes triggered by the Google base URL changing on
1404       // another client.  If the base URL changes in this client as well, we'll
1405       // pick that up separately at the appropriate time.  Otherwise, changing
1406       // the keyword here could result in having the wrong keyword for the local
1407       // environment.
1408       turl->data_.SetKeyword(existing_turl->keyword());
1409     }
1410   }
1411 
1412   return turl;
1413 }
1414 
1415 // static
CreateGUIDToSyncDataMap(const syncer::SyncDataList & sync_data)1416 SyncDataMap TemplateURLService::CreateGUIDToSyncDataMap(
1417     const syncer::SyncDataList& sync_data) {
1418   SyncDataMap data_map;
1419   for (auto i(sync_data.begin()); i != sync_data.end(); ++i)
1420     data_map[i->GetSpecifics().search_engine().sync_guid()] = *i;
1421   return data_map;
1422 }
1423 
Init(const Initializer * initializers,int num_initializers)1424 void TemplateURLService::Init(const Initializer* initializers,
1425                               int num_initializers) {
1426   if (client_)
1427     client_->SetOwner(this);
1428 
1429   if (prefs_) {
1430     pref_change_registrar_.Init(prefs_);
1431     pref_change_registrar_.Add(
1432         prefs::kSyncedDefaultSearchProviderGUID,
1433         base::Bind(
1434             &TemplateURLService::OnSyncedDefaultSearchProviderGUIDChanged,
1435             base::Unretained(this)));
1436   }
1437 
1438   DefaultSearchManager::Source source = DefaultSearchManager::FROM_USER;
1439   const TemplateURLData* dse =
1440       default_search_manager_.GetDefaultSearchEngine(&source);
1441 
1442   Scoper scoper(this);
1443 
1444   ApplyDefaultSearchChange(dse, source);
1445 
1446   if (num_initializers > 0) {
1447     // This path is only hit by test code and is used to simulate a loaded
1448     // TemplateURLService.
1449     ChangeToLoadedState();
1450 
1451     // Add specific initializers, if any.
1452     for (int i(0); i < num_initializers; ++i) {
1453       DCHECK(initializers[i].keyword);
1454       DCHECK(initializers[i].url);
1455       DCHECK(initializers[i].content);
1456 
1457       // TemplateURLService ends up owning the TemplateURL, don't try and free
1458       // it.
1459       TemplateURLData data;
1460       data.SetShortName(base::UTF8ToUTF16(initializers[i].content));
1461       data.SetKeyword(base::UTF8ToUTF16(initializers[i].keyword));
1462       data.SetURL(initializers[i].url);
1463       Add(std::make_unique<TemplateURL>(data));
1464 
1465       // Set the first provided identifier to be the default.
1466       if (i == 0)
1467         default_search_manager_.SetUserSelectedDefaultSearchEngine(data);
1468     }
1469   }
1470 }
1471 
RemoveFromMaps(const TemplateURL * template_url)1472 void TemplateURLService::RemoveFromMaps(const TemplateURL* template_url) {
1473   const base::string16& keyword = template_url->keyword();
1474 
1475   // Remove from |keyword_to_turl_and_length_|. No need to find the best
1476   // fallback. We choose the best one as-needed from the multimap.
1477   const auto match_range = keyword_to_turl_and_length_.equal_range(keyword);
1478   for (auto it = match_range.first; it != match_range.second;) {
1479     if (it->second.first == template_url) {
1480       it = keyword_to_turl_and_length_.erase(it);
1481     } else {
1482       ++it;
1483     }
1484   }
1485 
1486   if (template_url->type() == TemplateURL::OMNIBOX_API_EXTENSION)
1487     return;
1488 
1489   if (!template_url->sync_guid().empty())
1490     guid_to_turl_.erase(template_url->sync_guid());
1491   // |provider_map_| is only initialized after loading has completed.
1492   if (loaded_) {
1493     provider_map_->Remove(template_url);
1494   }
1495 }
1496 
AddToMaps(TemplateURL * template_url)1497 void TemplateURLService::AddToMaps(TemplateURL* template_url) {
1498   const base::string16& keyword = template_url->keyword();
1499   keyword_to_turl_and_length_.insert(std::make_pair(
1500       keyword,
1501       TURLAndMeaningfulLength(
1502           template_url, GetMeaningfulKeywordLength(keyword, template_url))));
1503 
1504   if (template_url->type() == TemplateURL::OMNIBOX_API_EXTENSION)
1505     return;
1506 
1507   if (!template_url->sync_guid().empty())
1508     guid_to_turl_[template_url->sync_guid()] = template_url;
1509   // |provider_map_| is only initialized after loading has completed.
1510   if (loaded_)
1511     provider_map_->Add(template_url, search_terms_data());
1512 }
1513 
SetTemplateURLs(std::unique_ptr<OwnedTemplateURLVector> urls)1514 void TemplateURLService::SetTemplateURLs(
1515     std::unique_ptr<OwnedTemplateURLVector> urls) {
1516   Scoper scoper(this);
1517 
1518   // Partition the URLs first, instead of implementing the loops below by simply
1519   // scanning the input twice.  While it's not supposed to happen normally, it's
1520   // possible for corrupt databases to return multiple entries with the same
1521   // keyword.  In this case, the first loop may delete the first entry when
1522   // adding the second.  If this happens, the second loop must not attempt to
1523   // access the deleted entry.  Partitioning ensures this constraint.
1524   auto first_invalid = std::partition(
1525       urls->begin(), urls->end(), [](const std::unique_ptr<TemplateURL>& turl) {
1526         return turl->id() != kInvalidTemplateURLID;
1527       });
1528 
1529   // First, add the items that already have id's, so that the next_id_ gets
1530   // properly set.
1531   for (auto i = urls->begin(); i != first_invalid; ++i) {
1532     next_id_ = std::max(next_id_, (*i)->id());
1533     Add(std::move(*i), false);
1534   }
1535 
1536   // Next add the new items that don't have id's.
1537   for (auto i = first_invalid; i != urls->end(); ++i)
1538     Add(std::move(*i));
1539 }
1540 
ChangeToLoadedState()1541 void TemplateURLService::ChangeToLoadedState() {
1542   DCHECK(!loaded_);
1543 
1544   provider_map_->Init(template_urls_, search_terms_data());
1545   loaded_ = true;
1546 
1547   ApplyDefaultSearchChangeNoMetrics(
1548       initial_default_search_provider_
1549           ? &initial_default_search_provider_->data()
1550           : nullptr,
1551       default_search_provider_source_);
1552   initial_default_search_provider_.reset();
1553 
1554   if (on_loaded_callback_for_sync_)
1555     std::move(on_loaded_callback_for_sync_).Run();
1556 
1557   on_loaded_callbacks_.Notify();
1558 }
1559 
CanAddAutogeneratedKeywordForHost(const std::string & host) const1560 bool TemplateURLService::CanAddAutogeneratedKeywordForHost(
1561     const std::string& host) const {
1562   const TemplateURLSet* urls = provider_map_->GetURLsForHost(host);
1563   if (!urls)
1564     return true;
1565 
1566   return std::all_of(urls->begin(), urls->end(), [](const TemplateURL* turl) {
1567     return turl->safe_for_autoreplace();
1568   });
1569 }
1570 
CanReplace(const TemplateURL * t_url) const1571 bool TemplateURLService::CanReplace(const TemplateURL* t_url) const {
1572   return !ShowInDefaultList(t_url) && t_url->safe_for_autoreplace();
1573 }
1574 
FindNonExtensionTemplateURLForKeyword(const base::string16 & keyword)1575 TemplateURL* TemplateURLService::FindNonExtensionTemplateURLForKeyword(
1576     const base::string16& keyword) {
1577   TemplateURL* keyword_turl = GetTemplateURLForKeyword(keyword);
1578   if (!keyword_turl || (keyword_turl->type() == TemplateURL::NORMAL))
1579     return keyword_turl;
1580   // The extension keyword in the model may be hiding a replaceable
1581   // non-extension keyword.  Look for it.
1582   for (const auto& turl : template_urls_) {
1583     if ((turl->type() == TemplateURL::NORMAL) &&
1584         (turl->keyword() == keyword))
1585       return turl.get();
1586   }
1587   return nullptr;
1588 }
1589 
Update(TemplateURL * existing_turl,const TemplateURL & new_values)1590 bool TemplateURLService::Update(TemplateURL* existing_turl,
1591                                 const TemplateURL& new_values) {
1592   DCHECK(existing_turl);
1593   DCHECK(!IsCreatedByExtension(existing_turl));
1594   if (!Contains(&template_urls_, existing_turl))
1595     return false;
1596 
1597   Scoper scoper(this);
1598   model_mutated_notification_pending_ = true;
1599 
1600   TemplateURLID previous_id = existing_turl->id();
1601   RemoveFromMaps(existing_turl);
1602 
1603   // Check for new keyword conflicts with another normal engine.
1604   // This is possible when autogeneration of the keyword for a Google default
1605   // search provider at load time causes it to conflict with an existing
1606   // keyword. If the conflicting engines are replaceable, we delete them.
1607   // If they're not replaceable, we leave them alone, and trust AddToMaps() to
1608   // choose the best engine to assign the keyword.
1609   std::vector<TemplateURL*> turls_to_remove;
1610   for (const auto& turl : template_urls_) {
1611     // TODO(tommycli): Investigate also replacing TemplateURL::LOCAL engines.
1612     if (turl.get() != existing_turl && (turl->type() == TemplateURL::NORMAL) &&
1613         (turl->keyword() == new_values.keyword()) && CanReplace(turl.get())) {
1614       // Remove() invalidates iterators.
1615       turls_to_remove.push_back(turl.get());
1616     }
1617   }
1618   for (TemplateURL* turl : turls_to_remove) {
1619     Remove(turl);
1620   }
1621 
1622   // Update existing turl with new values. This must happen after calling
1623   // Remove(conflicting_keyword_turl) above, since otherwise during that
1624   // function RemoveFromMaps() may find |existing_turl| as an alternate engine
1625   // for the same keyword.  Duplicate keyword handling is only meant for the
1626   // case of extensions, and if done here would leave internal state
1627   // inconsistent (e.g. |existing_turl| would already be re-added to maps before
1628   // calling AddToMaps() below).
1629   existing_turl->CopyFrom(new_values);
1630   existing_turl->data_.id = previous_id;
1631 
1632   AddToMaps(existing_turl);
1633 
1634   if (existing_turl->type() == TemplateURL::NORMAL) {
1635     if (web_data_service_)
1636       web_data_service_->UpdateKeyword(existing_turl->data());
1637 
1638     // Inform sync of the update.
1639     ProcessTemplateURLChange(FROM_HERE, existing_turl,
1640                              syncer::SyncChange::ACTION_UPDATE);
1641   }
1642 
1643   // Even if the DSE is controlled by an extension or policy, update the user
1644   // preferences as they may take over later.
1645   if (default_search_provider_source_ != DefaultSearchManager::FROM_FALLBACK)
1646     MaybeUpdateDSEViaPrefs(existing_turl);
1647 
1648   return true;
1649 }
1650 
1651 // static
UpdateTemplateURLIfPrepopulated(TemplateURL * template_url,PrefService * prefs)1652 void TemplateURLService::UpdateTemplateURLIfPrepopulated(
1653     TemplateURL* template_url,
1654     PrefService* prefs) {
1655   int prepopulate_id = template_url->prepopulate_id();
1656   if (template_url->prepopulate_id() == 0)
1657     return;
1658 
1659   std::vector<std::unique_ptr<TemplateURLData>> prepopulated_urls =
1660       TemplateURLPrepopulateData::GetPrepopulatedEngines(prefs, nullptr);
1661 
1662   for (const auto& url : prepopulated_urls) {
1663     if (url->prepopulate_id == prepopulate_id) {
1664       MergeIntoPrepopulatedEngineData(template_url, url.get());
1665       template_url->CopyFrom(TemplateURL(*url));
1666     }
1667   }
1668 }
1669 
MaybeUpdateDSEViaPrefs(TemplateURL * synced_turl)1670 void TemplateURLService::MaybeUpdateDSEViaPrefs(TemplateURL* synced_turl) {
1671   if (prefs_ &&
1672       (synced_turl->sync_guid() ==
1673           prefs_->GetString(prefs::kSyncedDefaultSearchProviderGUID))) {
1674     default_search_manager_.SetUserSelectedDefaultSearchEngine(
1675         synced_turl->data());
1676   }
1677 }
1678 
UpdateKeywordSearchTermsForURL(const URLVisitedDetails & details)1679 void TemplateURLService::UpdateKeywordSearchTermsForURL(
1680     const URLVisitedDetails& details) {
1681   if (!details.url.is_valid())
1682     return;
1683 
1684   const TemplateURLSet* urls_for_host =
1685       provider_map_->GetURLsForHost(details.url.host());
1686   if (!urls_for_host)
1687     return;
1688 
1689   TemplateURL* visited_url = nullptr;
1690   for (auto i = urls_for_host->begin(); i != urls_for_host->end(); ++i) {
1691     base::string16 search_terms;
1692     if ((*i)->ExtractSearchTermsFromURL(details.url, search_terms_data(),
1693                                         &search_terms) &&
1694         !search_terms.empty()) {
1695       if (details.is_keyword_transition) {
1696         // The visit is the result of the user entering a keyword, generate a
1697         // KEYWORD_GENERATED visit for the KEYWORD so that the keyword typed
1698         // count is boosted.
1699         AddTabToSearchVisit(**i);
1700       }
1701       if (client_) {
1702         client_->SetKeywordSearchTermsForURL(
1703             details.url, (*i)->id(), search_terms);
1704       }
1705       // Caches the matched TemplateURL so its last_visited could be updated
1706       // later after iteration.
1707       // Note: Update() will replace the entry from the container of this
1708       // iterator, so update here directly will cause an error about it.
1709       if (!IsCreatedByExtension(*i))
1710         visited_url = *i;
1711     }
1712   }
1713   if (visited_url)
1714     UpdateTemplateURLVisitTime(visited_url);
1715 }
1716 
UpdateTemplateURLVisitTime(TemplateURL * url)1717 void TemplateURLService::UpdateTemplateURLVisitTime(TemplateURL* url) {
1718   TemplateURLData data(url->data());
1719   data.last_visited = clock_->Now();
1720   Update(url, TemplateURL(data));
1721 }
1722 
AddTabToSearchVisit(const TemplateURL & t_url)1723 void TemplateURLService::AddTabToSearchVisit(const TemplateURL& t_url) {
1724   // Only add visits for entries the user hasn't modified. If the user modified
1725   // the entry the keyword may no longer correspond to the host name. It may be
1726   // possible to do something more sophisticated here, but it's so rare as to
1727   // not be worth it.
1728   if (!t_url.safe_for_autoreplace())
1729     return;
1730 
1731   if (!client_)
1732     return;
1733 
1734   GURL url(url_formatter::FixupURL(base::UTF16ToUTF8(t_url.keyword()),
1735                                    std::string()));
1736   if (!url.is_valid())
1737     return;
1738 
1739   // Synthesize a visit for the keyword. This ensures the url for the keyword is
1740   // autocompleted even if the user doesn't type the url in directly.
1741   client_->AddKeywordGeneratedVisit(url);
1742 }
1743 
ApplyDefaultSearchChange(const TemplateURLData * data,DefaultSearchManager::Source source)1744 void TemplateURLService::ApplyDefaultSearchChange(
1745     const TemplateURLData* data,
1746     DefaultSearchManager::Source source) {
1747   if (!ApplyDefaultSearchChangeNoMetrics(data, source))
1748     return;
1749 
1750   UMA_HISTOGRAM_ENUMERATION(
1751       "Search.DefaultSearchChangeOrigin", dsp_change_origin_, DSP_CHANGE_MAX);
1752 
1753   if (GetDefaultSearchProvider() &&
1754       GetDefaultSearchProvider()->HasGoogleBaseURLs(search_terms_data()) &&
1755       !dsp_change_callback_.is_null())
1756     dsp_change_callback_.Run();
1757 }
1758 
ApplyDefaultSearchChangeNoMetrics(const TemplateURLData * data,DefaultSearchManager::Source source)1759 bool TemplateURLService::ApplyDefaultSearchChangeNoMetrics(
1760     const TemplateURLData* data,
1761     DefaultSearchManager::Source source) {
1762   // We do not want any sort of reentrancy while changing the default search
1763   // engine. This can occur when resolving conflicting entries. In those cases,
1764   // it's best to early exit and let the original process finish.
1765   if (applying_default_search_engine_change_)
1766     return false;
1767   base::AutoReset<bool> applying_change(&applying_default_search_engine_change_,
1768                                         true);
1769 
1770   if (!loaded_) {
1771     // Set |initial_default_search_provider_| from the preferences. This is
1772     // mainly so we can hold ownership until we get to the point where the list
1773     // of keywords from Web Data is the owner of everything including the
1774     // default.
1775     bool changed = !TemplateURL::MatchesData(
1776         initial_default_search_provider_.get(), data, search_terms_data());
1777     TemplateURL::Type initial_engine_type =
1778         (source == DefaultSearchManager::FROM_EXTENSION)
1779             ? TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION
1780             : TemplateURL::NORMAL;
1781     initial_default_search_provider_ =
1782         data ? std::make_unique<TemplateURL>(*data, initial_engine_type)
1783              : nullptr;
1784     default_search_provider_source_ = source;
1785     return changed;
1786   }
1787 
1788   // This may be deleted later. Use exclusively for pointer comparison to detect
1789   // a change.
1790   TemplateURL* previous_default_search_engine = default_search_provider_;
1791 
1792   Scoper scoper(this);
1793 
1794   if (default_search_provider_source_ == DefaultSearchManager::FROM_POLICY ||
1795       source == DefaultSearchManager::FROM_POLICY) {
1796     // We do this both to remove any no-longer-applicable policy-defined DSE as
1797     // well as to add the new one, if appropriate.
1798     UpdateProvidersCreatedByPolicy(
1799         &template_urls_,
1800         source == DefaultSearchManager::FROM_POLICY ? data : nullptr);
1801   }
1802 
1803   // |default_search_provider_source_| must be set before calling Update(),
1804   // since that function needs to know the source of the update in question.
1805   default_search_provider_source_ = source;
1806 
1807   if (!data) {
1808     default_search_provider_ = nullptr;
1809   } else if (source == DefaultSearchManager::FROM_EXTENSION) {
1810     default_search_provider_ = FindMatchingDefaultExtensionTemplateURL(*data);
1811     DCHECK(default_search_provider_);
1812   } else if (source == DefaultSearchManager::FROM_FALLBACK) {
1813     default_search_provider_ =
1814         FindPrepopulatedTemplateURL(data->prepopulate_id);
1815     if (default_search_provider_) {
1816       TemplateURLData update_data(*data);
1817       update_data.sync_guid = default_search_provider_->sync_guid();
1818 
1819       // Now that we are auto-updating the favicon_url as the user browses,
1820       // respect the favicon_url entry in the database, instead of falling back
1821       // to the one in the prepopulated list.
1822       update_data.favicon_url = default_search_provider_->favicon_url();
1823 
1824       if (!default_search_provider_->safe_for_autoreplace()) {
1825         update_data.safe_for_autoreplace = false;
1826         update_data.SetKeyword(default_search_provider_->keyword());
1827         update_data.SetShortName(default_search_provider_->short_name());
1828       }
1829       Update(default_search_provider_, TemplateURL(update_data));
1830     } else {
1831       // Normally the prepopulated fallback should be present in
1832       // |template_urls_|, but in a few cases it might not be:
1833       // (1) Tests that initialize the TemplateURLService in peculiar ways.
1834       // (2) If the user deleted the pre-populated default and we subsequently
1835       // lost their user-selected value.
1836       default_search_provider_ = Add(std::make_unique<TemplateURL>(*data));
1837     }
1838   } else if (source == DefaultSearchManager::FROM_USER) {
1839     default_search_provider_ = GetTemplateURLForGUID(data->sync_guid);
1840     if (!default_search_provider_ && data->prepopulate_id) {
1841       default_search_provider_ =
1842           FindPrepopulatedTemplateURL(data->prepopulate_id);
1843     }
1844     TemplateURLData new_data(*data);
1845     if (default_search_provider_) {
1846       Update(default_search_provider_, TemplateURL(new_data));
1847     } else {
1848       new_data.id = kInvalidTemplateURLID;
1849       default_search_provider_ = Add(std::make_unique<TemplateURL>(new_data));
1850     }
1851     if (default_search_provider_ && prefs_) {
1852       prefs_->SetString(prefs::kSyncedDefaultSearchProviderGUID,
1853                         default_search_provider_->sync_guid());
1854     }
1855   }
1856 
1857   bool changed = default_search_provider_ != previous_default_search_engine;
1858   if (changed) {
1859     model_mutated_notification_pending_ = true;
1860   }
1861 
1862   return changed;
1863 }
1864 
Add(std::unique_ptr<TemplateURL> template_url,bool newly_adding)1865 TemplateURL* TemplateURLService::Add(std::unique_ptr<TemplateURL> template_url,
1866                                      bool newly_adding) {
1867   DCHECK(template_url);
1868 
1869   Scoper scoper(this);
1870 
1871   if (newly_adding) {
1872     DCHECK_EQ(kInvalidTemplateURLID, template_url->id());
1873     DCHECK(!Contains(&template_urls_, template_url.get()));
1874     template_url->data_.id = ++next_id_;
1875   }
1876 
1877   template_url->ResetKeywordIfNecessary(search_terms_data(), false);
1878 
1879   // If |template_url| is not created by an extension, its keyword must not
1880   // conflict with any already in the model.
1881   if (!IsCreatedByExtension(template_url.get())) {
1882     TemplateURL* existing_turl =
1883         FindNonExtensionTemplateURLForKeyword(template_url->keyword());
1884 
1885     // Note that we can reach here during the loading phase while processing the
1886     // template URLs from the web data service.  In this case,
1887     // GetTemplateURLForKeyword() will look not only at what's already in the
1888     // model, but at the |initial_default_search_provider_|.  Since this engine
1889     // will presumably also be present in the web data, we need to double-check
1890     // that any "pre-existing" entries we find are actually coming from
1891     // |template_urls_|, lest we detect a "conflict" between the
1892     // |initial_default_search_provider_| and the web data version of itself.
1893     if (existing_turl && Contains(&template_urls_, existing_turl)) {
1894       DCHECK_NE(existing_turl, template_url.get());
1895       if (CanReplace(existing_turl)) {
1896         Remove(existing_turl);
1897       } else if (CanReplace(template_url.get())) {
1898         return nullptr;
1899       } else {
1900         // Neither engine can be replaced. Uniquify the existing keyword.
1901         base::string16 new_keyword = UniquifyKeyword(*existing_turl, false);
1902         ResetTemplateURL(existing_turl, existing_turl->short_name(),
1903                          new_keyword, existing_turl->url());
1904         DCHECK_EQ(new_keyword, existing_turl->keyword());
1905       }
1906     }
1907   }
1908   TemplateURL* template_url_ptr = template_url.get();
1909   template_urls_.push_back(std::move(template_url));
1910   AddToMaps(template_url_ptr);
1911 
1912   if (newly_adding && (template_url_ptr->type() == TemplateURL::NORMAL)) {
1913     if (web_data_service_)
1914       web_data_service_->AddKeyword(template_url_ptr->data());
1915 
1916     // Inform sync of the addition. Note that this will assign a GUID to
1917     // template_url and add it to the guid_to_turl_.
1918     ProcessTemplateURLChange(FROM_HERE, template_url_ptr,
1919                              syncer::SyncChange::ACTION_ADD);
1920   }
1921 
1922   if (template_url_ptr)
1923     model_mutated_notification_pending_ = true;
1924 
1925   return template_url_ptr;
1926 }
1927 
1928 // |template_urls| are the TemplateURLs loaded from the database.
1929 // |default_from_prefs| is the default search provider from the preferences, or
1930 // NULL if the DSE is not policy-defined.
1931 //
1932 // This function removes from the vector and the database all the TemplateURLs
1933 // that were set by policy, unless it is the current default search provider, in
1934 // which case it is updated with the data from prefs.
UpdateProvidersCreatedByPolicy(OwnedTemplateURLVector * template_urls,const TemplateURLData * default_from_prefs)1935 void TemplateURLService::UpdateProvidersCreatedByPolicy(
1936     OwnedTemplateURLVector* template_urls,
1937     const TemplateURLData* default_from_prefs) {
1938   DCHECK(template_urls);
1939 
1940   Scoper scoper(this);
1941 
1942   for (auto i = template_urls->begin(); i != template_urls->end();) {
1943     TemplateURL* template_url = i->get();
1944     if (template_url->created_by_policy()) {
1945       if (default_from_prefs &&
1946           TemplateURL::MatchesData(template_url, default_from_prefs,
1947                                    search_terms_data())) {
1948         // If the database specified a default search provider that was set
1949         // by policy, and the default search provider from the preferences
1950         // is also set by policy and they are the same, keep the entry in the
1951         // database and the |default_search_provider|.
1952         default_search_provider_ = template_url;
1953         // Prevent us from saving any other entries, or creating a new one.
1954         default_from_prefs = nullptr;
1955         ++i;
1956         continue;
1957       }
1958 
1959       TemplateURLID id = template_url->id();
1960       RemoveFromMaps(template_url);
1961       i = template_urls->erase(i);
1962       if (web_data_service_)
1963         web_data_service_->RemoveKeyword(id);
1964     } else {
1965       ++i;
1966     }
1967   }
1968 
1969   if (default_from_prefs) {
1970     default_search_provider_ = nullptr;
1971     default_search_provider_source_ = DefaultSearchManager::FROM_POLICY;
1972     TemplateURLData new_data(*default_from_prefs);
1973     if (new_data.sync_guid.empty())
1974       new_data.GenerateSyncGUID();
1975     new_data.created_by_policy = true;
1976     std::unique_ptr<TemplateURL> new_dse_ptr =
1977         std::make_unique<TemplateURL>(new_data);
1978     TemplateURL* new_dse = new_dse_ptr.get();
1979     if (Add(std::move(new_dse_ptr)))
1980       default_search_provider_ = new_dse;
1981   }
1982 }
1983 
ResetTemplateURLGUID(TemplateURL * url,const std::string & guid)1984 void TemplateURLService::ResetTemplateURLGUID(TemplateURL* url,
1985                                               const std::string& guid) {
1986   DCHECK(loaded_);
1987   DCHECK(!guid.empty());
1988 
1989   TemplateURLData data(url->data());
1990   data.sync_guid = guid;
1991   Update(url, TemplateURL(data));
1992 }
1993 
UniquifyKeyword(const TemplateURL & turl,bool force)1994 base::string16 TemplateURLService::UniquifyKeyword(const TemplateURL& turl,
1995                                                    bool force) {
1996   DCHECK(!IsCreatedByExtension(&turl));
1997   if (!force) {
1998     // Already unique.
1999     if (!GetTemplateURLForKeyword(turl.keyword()))
2000       return turl.keyword();
2001 
2002     // First, try to return the generated keyword for the TemplateURL.
2003     GURL gurl(turl.url());
2004     if (gurl.is_valid()) {
2005       base::string16 keyword_candidate = TemplateURL::GenerateKeyword(gurl);
2006       if (!GetTemplateURLForKeyword(keyword_candidate))
2007         return keyword_candidate;
2008     }
2009   }
2010 
2011   // We try to uniquify the keyword by appending a special character to the end.
2012   // This is a best-effort approach where we try to preserve the original
2013   // keyword and let the user do what they will after our attempt.
2014   base::string16 keyword_candidate(turl.keyword());
2015   do {
2016     keyword_candidate.append(base::ASCIIToUTF16("_"));
2017   } while (GetTemplateURLForKeyword(keyword_candidate));
2018 
2019   return keyword_candidate;
2020 }
2021 
IsLocalTemplateURLBetter(const TemplateURL * local_turl,const TemplateURL * sync_turl,bool prefer_local_default) const2022 bool TemplateURLService::IsLocalTemplateURLBetter(
2023     const TemplateURL* local_turl,
2024     const TemplateURL* sync_turl,
2025     bool prefer_local_default) const {
2026   DCHECK(GetTemplateURLForGUID(local_turl->sync_guid()));
2027   return local_turl->last_modified() > sync_turl->last_modified() ||
2028          local_turl->created_by_policy() ||
2029          (prefer_local_default && local_turl == GetDefaultSearchProvider());
2030 }
2031 
ResolveSyncKeywordConflict(TemplateURL * unapplied_sync_turl,TemplateURL * applied_sync_turl,syncer::SyncChangeList * change_list)2032 void TemplateURLService::ResolveSyncKeywordConflict(
2033     TemplateURL* unapplied_sync_turl,
2034     TemplateURL* applied_sync_turl,
2035     syncer::SyncChangeList* change_list) {
2036   DCHECK(loaded_);
2037   DCHECK(unapplied_sync_turl);
2038   DCHECK(applied_sync_turl);
2039   DCHECK(change_list);
2040   DCHECK_EQ(applied_sync_turl->keyword(), unapplied_sync_turl->keyword());
2041   DCHECK_EQ(TemplateURL::NORMAL, applied_sync_turl->type());
2042 
2043   Scoper scoper(this);
2044 
2045   // Both |unapplied_sync_turl| and |applied_sync_turl| are known to Sync, so
2046   // don't delete either of them. Instead, determine which is "better" and
2047   // uniquify the other one, sending an update to the server for the updated
2048   // entry.
2049   const bool applied_turl_is_better =
2050       IsLocalTemplateURLBetter(applied_sync_turl, unapplied_sync_turl);
2051   TemplateURL* loser = applied_turl_is_better ?
2052       unapplied_sync_turl : applied_sync_turl;
2053   base::string16 new_keyword = UniquifyKeyword(*loser, false);
2054   DCHECK(!GetTemplateURLForKeyword(new_keyword));
2055   if (applied_turl_is_better) {
2056     // Just set the keyword of |unapplied_sync_turl|. The caller is responsible
2057     // for adding or updating unapplied_sync_turl in the local model.
2058     unapplied_sync_turl->data_.SetKeyword(new_keyword);
2059   } else {
2060     // Update |applied_sync_turl| in the local model with the new keyword.
2061     TemplateURLData data(applied_sync_turl->data());
2062     data.SetKeyword(new_keyword);
2063     Update(applied_sync_turl, TemplateURL(data));
2064   }
2065   // The losing TemplateURL should have their keyword updated. Send a change to
2066   // the server to reflect this change.
2067   syncer::SyncData sync_data = CreateSyncDataFromTemplateURL(*loser);
2068   change_list->push_back(syncer::SyncChange(FROM_HERE,
2069       syncer::SyncChange::ACTION_UPDATE,
2070       sync_data));
2071 }
2072 
MergeInSyncTemplateURL(TemplateURL * sync_turl,const SyncDataMap & sync_data,syncer::SyncChangeList * change_list,SyncDataMap * local_data)2073 void TemplateURLService::MergeInSyncTemplateURL(
2074     TemplateURL* sync_turl,
2075     const SyncDataMap& sync_data,
2076     syncer::SyncChangeList* change_list,
2077     SyncDataMap* local_data) {
2078   DCHECK(sync_turl);
2079   DCHECK(!GetTemplateURLForGUID(sync_turl->sync_guid()));
2080   DCHECK(IsFromSync(sync_turl, sync_data));
2081 
2082   TemplateURL* conflicting_turl =
2083       FindNonExtensionTemplateURLForKeyword(sync_turl->keyword());
2084   bool should_add_sync_turl = true;
2085 
2086   Scoper scoper(this);
2087 
2088   // Resolve conflicts with local TemplateURLs.
2089   if (conflicting_turl) {
2090     // Modify |conflicting_turl| to make room for |sync_turl|.
2091     if (IsFromSync(conflicting_turl, sync_data)) {
2092       // |conflicting_turl| is already known to Sync, so we're not allowed to
2093       // remove it. In this case, we want to uniquify the worse one and send an
2094       // update for the changed keyword to sync. We can reuse the logic from
2095       // ResolveSyncKeywordConflict for this.
2096       ResolveSyncKeywordConflict(sync_turl, conflicting_turl, change_list);
2097     } else {
2098       // |conflicting_turl| is not yet known to Sync. If it is better, then we
2099       // want to transfer its values up to sync. Otherwise, we remove it and
2100       // allow the entry from Sync to overtake it in the model.
2101       const std::string guid = conflicting_turl->sync_guid();
2102       if (IsLocalTemplateURLBetter(conflicting_turl, sync_turl)) {
2103         ResetTemplateURLGUID(conflicting_turl, sync_turl->sync_guid());
2104         syncer::SyncData sync_data =
2105             CreateSyncDataFromTemplateURL(*conflicting_turl);
2106         change_list->push_back(syncer::SyncChange(
2107             FROM_HERE, syncer::SyncChange::ACTION_UPDATE, sync_data));
2108         // Note that in this case we do not add the Sync TemplateURL to the
2109         // local model, since we've effectively "merged" it in by updating the
2110         // local conflicting entry with its sync_guid.
2111         should_add_sync_turl = false;
2112       } else {
2113         // We guarantee that this isn't the local search provider. Otherwise,
2114         // local would have won.
2115         DCHECK(conflicting_turl != GetDefaultSearchProvider());
2116         Remove(conflicting_turl);
2117       }
2118       // This TemplateURL was either removed or overwritten in the local model.
2119       // Remove the entry from the local data so it isn't pushed up to Sync.
2120       local_data->erase(guid);
2121     }
2122     // prepopulate_id 0 effectively means unspecified; i.e. that the turl isn't
2123     // a pre-populated one, so we want to ignore that case.
2124   } else if (sync_turl->prepopulate_id() != 0) {
2125     // Check for a turl with a conflicting prepopulate_id. This detects the case
2126     // where the user changes a prepopulated engine's keyword on one client,
2127     // then begins syncing on another client.  We want to reflect this keyword
2128     // change to that prepopulated URL on other clients instead of assuming that
2129     // the modified TemplateURL is a new entity.
2130     TemplateURL* conflicting_prepopulated_turl =
2131         FindPrepopulatedTemplateURL(sync_turl->prepopulate_id());
2132 
2133     // If we found a conflict, and the sync entity is better, apply the remote
2134     // changes locally. We consider |sync_turl| better if it's been modified
2135     // more recently and the local TemplateURL isn't yet known to sync. We will
2136     // consider the sync entity better even if the local TemplateURL is the
2137     // current default, since in this case being default does not necessarily
2138     // mean the user explicitly set this TemplateURL as default. If we didn't do
2139     // this, changes to the keywords of prepopulated default engines would never
2140     // be applied to other clients.
2141     // If we can't safely replace the local entry with the synced one, or merge
2142     // the relevant changes in, we give up and leave both intact.
2143     if (conflicting_prepopulated_turl &&
2144         !IsFromSync(conflicting_prepopulated_turl, sync_data) &&
2145         !IsLocalTemplateURLBetter(conflicting_prepopulated_turl, sync_turl,
2146                                   false)) {
2147       std::string guid = conflicting_prepopulated_turl->sync_guid();
2148       if (conflicting_prepopulated_turl == default_search_provider_) {
2149         bool pref_matched =
2150             prefs_->GetString(prefs::kSyncedDefaultSearchProviderGUID) ==
2151             default_search_provider_->sync_guid();
2152         // Update the existing engine in-place.
2153         Update(default_search_provider_, TemplateURL(sync_turl->data()));
2154         // If prefs::kSyncedDefaultSearchProviderGUID matched
2155         // |default_search_provider_|'s GUID before, then update it to match its
2156         // new GUID. If the pref didn't match before, then it probably refers to
2157         // a new search engine from Sync which just hasn't been added locally
2158         // yet, so leave it alone in that case.
2159         if (pref_matched) {
2160           prefs_->SetString(prefs::kSyncedDefaultSearchProviderGUID,
2161                             default_search_provider_->sync_guid());
2162         }
2163 
2164         should_add_sync_turl = false;
2165       } else {
2166         Remove(conflicting_prepopulated_turl);
2167       }
2168       // Remove the local data so it isn't written to sync.
2169       local_data->erase(guid);
2170     }
2171   }
2172 
2173   if (should_add_sync_turl) {
2174     // Force the local ID to kInvalidTemplateURLID so we can add it.
2175     TemplateURLData data(sync_turl->data());
2176     data.id = kInvalidTemplateURLID;
2177     std::unique_ptr<TemplateURL> added_ptr =
2178         std::make_unique<TemplateURL>(data);
2179     TemplateURL* added = added_ptr.get();
2180     base::AutoReset<DefaultSearchChangeOrigin> change_origin(
2181         &dsp_change_origin_, DSP_CHANGE_SYNC_ADD);
2182     if (Add(std::move(added_ptr)))
2183       MaybeUpdateDSEViaPrefs(added);
2184   }
2185 }
2186 
PatchMissingSyncGUIDs(OwnedTemplateURLVector * template_urls)2187 void TemplateURLService::PatchMissingSyncGUIDs(
2188     OwnedTemplateURLVector* template_urls) {
2189   DCHECK(template_urls);
2190   for (auto& template_url : *template_urls) {
2191     DCHECK(template_url);
2192     if (template_url->sync_guid().empty() &&
2193         (template_url->type() == TemplateURL::NORMAL)) {
2194       template_url->data_.GenerateSyncGUID();
2195       if (web_data_service_)
2196         web_data_service_->UpdateKeyword(template_url->data());
2197     }
2198   }
2199 }
2200 
OnSyncedDefaultSearchProviderGUIDChanged()2201 void TemplateURLService::OnSyncedDefaultSearchProviderGUIDChanged() {
2202   base::AutoReset<DefaultSearchChangeOrigin> change_origin(
2203       &dsp_change_origin_, DSP_CHANGE_SYNC_PREF);
2204 
2205   std::string new_guid =
2206       prefs_->GetString(prefs::kSyncedDefaultSearchProviderGUID);
2207   if (new_guid.empty()) {
2208     default_search_manager_.ClearUserSelectedDefaultSearchEngine();
2209     return;
2210   }
2211 
2212   const TemplateURL* turl = GetTemplateURLForGUID(new_guid);
2213   if (turl)
2214     default_search_manager_.SetUserSelectedDefaultSearchEngine(turl->data());
2215 }
2216 
2217 template <typename Container>
AddMatchingKeywordsHelper(const Container & keyword_to_turl_and_length,const base::string16 & prefix,bool supports_replacement_only,TURLsAndMeaningfulLengths * matches)2218 void TemplateURLService::AddMatchingKeywordsHelper(
2219     const Container& keyword_to_turl_and_length,
2220     const base::string16& prefix,
2221     bool supports_replacement_only,
2222     TURLsAndMeaningfulLengths* matches) {
2223   // Sanity check args.
2224   if (prefix.empty())
2225     return;
2226   DCHECK(matches);
2227 
2228   // Find matching keyword range.  Searches the element map for keywords
2229   // beginning with |prefix| and stores the endpoints of the resulting set in
2230   // |match_range|.
2231   const auto match_range(std::equal_range(
2232       keyword_to_turl_and_length.begin(), keyword_to_turl_and_length.end(),
2233       typename Container::value_type(prefix,
2234                                      TURLAndMeaningfulLength(nullptr, 0)),
2235       LessWithPrefix()));
2236 
2237   // Add to vector of matching keywords.
2238   for (typename Container::const_iterator i(match_range.first);
2239     i != match_range.second; ++i) {
2240     if (!supports_replacement_only ||
2241         i->second.first->url_ref().SupportsReplacement(search_terms_data()))
2242       matches->push_back(i->second);
2243   }
2244 }
2245 
FindPrepopulatedTemplateURL(int prepopulated_id)2246 TemplateURL* TemplateURLService::FindPrepopulatedTemplateURL(
2247     int prepopulated_id) {
2248   DCHECK(prepopulated_id);
2249   for (const auto& turl : template_urls_) {
2250     if (turl->prepopulate_id() == prepopulated_id)
2251       return turl.get();
2252   }
2253   return nullptr;
2254 }
2255 
FindTemplateURLForExtension(const std::string & extension_id,TemplateURL::Type type)2256 TemplateURL* TemplateURLService::FindTemplateURLForExtension(
2257     const std::string& extension_id,
2258     TemplateURL::Type type) {
2259   DCHECK_NE(TemplateURL::NORMAL, type);
2260   for (const auto& turl : template_urls_) {
2261     if (turl->type() == type && turl->GetExtensionId() == extension_id)
2262       return turl.get();
2263   }
2264   return nullptr;
2265 }
2266 
FindMatchingDefaultExtensionTemplateURL(const TemplateURLData & data)2267 TemplateURL* TemplateURLService::FindMatchingDefaultExtensionTemplateURL(
2268     const TemplateURLData& data) {
2269   for (const auto& turl : template_urls_) {
2270     if (turl->type() == TemplateURL::NORMAL_CONTROLLED_BY_EXTENSION &&
2271         turl->extension_info_->wants_to_be_default_engine &&
2272         TemplateURL::MatchesData(turl.get(), &data, search_terms_data()))
2273       return turl.get();
2274   }
2275   return nullptr;
2276 }
2277