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/default_search_manager.h"
6
7 #include <algorithm>
8 #include <utility>
9
10 #include "base/bind.h"
11 #include "base/bind_helpers.h"
12 #include "base/compiler_specific.h"
13 #include "base/i18n/case_conversion.h"
14 #include "base/logging.h"
15 #include "base/prefs/pref_service.h"
16 #include "base/prefs/pref_value_map.h"
17 #include "base/stl_util.h"
18 #include "base/strings/string_number_conversions.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 "base/time/time.h"
23 #include "components/pref_registry/pref_registry_syncable.h"
24 #include "components/search_engines/search_engines_pref_names.h"
25 #include "components/search_engines/template_url_data.h"
26 #include "components/search_engines/template_url_prepopulate_data.h"
27
28 namespace {
29
30 bool g_fallback_search_engines_disabled = false;
31
32 } // namespace
33
34 // A dictionary to hold all data related to the Default Search Engine.
35 // Eventually, this should replace all the data stored in the
36 // default_search_provider.* prefs.
37 const char DefaultSearchManager::kDefaultSearchProviderDataPrefName[] =
38 "default_search_provider_data.template_url_data";
39
40 const char DefaultSearchManager::kID[] = "id";
41 const char DefaultSearchManager::kShortName[] = "short_name";
42 const char DefaultSearchManager::kKeyword[] = "keyword";
43 const char DefaultSearchManager::kPrepopulateID[] = "prepopulate_id";
44 const char DefaultSearchManager::kSyncGUID[] = "synced_guid";
45
46 const char DefaultSearchManager::kURL[] = "url";
47 const char DefaultSearchManager::kSuggestionsURL[] = "suggestions_url";
48 const char DefaultSearchManager::kInstantURL[] = "instant_url";
49 const char DefaultSearchManager::kImageURL[] = "image_url";
50 const char DefaultSearchManager::kNewTabURL[] = "new_tab_url";
51 const char DefaultSearchManager::kFaviconURL[] = "favicon_url";
52 const char DefaultSearchManager::kOriginatingURL[] = "originating_url";
53
54 const char DefaultSearchManager::kSearchURLPostParams[] =
55 "search_url_post_params";
56 const char DefaultSearchManager::kSuggestionsURLPostParams[] =
57 "suggestions_url_post_params";
58 const char DefaultSearchManager::kInstantURLPostParams[] =
59 "instant_url_post_params";
60 const char DefaultSearchManager::kImageURLPostParams[] =
61 "image_url_post_params";
62
63 const char DefaultSearchManager::kSafeForAutoReplace[] = "safe_for_autoreplace";
64 const char DefaultSearchManager::kInputEncodings[] = "input_encodings";
65
66 const char DefaultSearchManager::kDateCreated[] = "date_created";
67 const char DefaultSearchManager::kLastModified[] = "last_modified";
68
69 const char DefaultSearchManager::kUsageCount[] = "usage_count";
70 const char DefaultSearchManager::kAlternateURLs[] = "alternate_urls";
71 const char DefaultSearchManager::kSearchTermsReplacementKey[] =
72 "search_terms_replacement_key";
73 const char DefaultSearchManager::kCreatedByPolicy[] = "created_by_policy";
74 const char DefaultSearchManager::kDisabledByPolicy[] = "disabled_by_policy";
75
DefaultSearchManager(PrefService * pref_service,const ObserverCallback & change_observer)76 DefaultSearchManager::DefaultSearchManager(
77 PrefService* pref_service,
78 const ObserverCallback& change_observer)
79 : pref_service_(pref_service),
80 change_observer_(change_observer),
81 default_search_controlled_by_policy_(false) {
82 if (pref_service_) {
83 pref_change_registrar_.Init(pref_service_);
84 pref_change_registrar_.Add(
85 kDefaultSearchProviderDataPrefName,
86 base::Bind(&DefaultSearchManager::OnDefaultSearchPrefChanged,
87 base::Unretained(this)));
88 pref_change_registrar_.Add(
89 prefs::kSearchProviderOverrides,
90 base::Bind(&DefaultSearchManager::OnOverridesPrefChanged,
91 base::Unretained(this)));
92 }
93 LoadPrepopulatedDefaultSearch();
94 LoadDefaultSearchEngineFromPrefs();
95 }
96
~DefaultSearchManager()97 DefaultSearchManager::~DefaultSearchManager() {
98 }
99
100 // static
RegisterProfilePrefs(user_prefs::PrefRegistrySyncable * registry)101 void DefaultSearchManager::RegisterProfilePrefs(
102 user_prefs::PrefRegistrySyncable* registry) {
103 registry->RegisterDictionaryPref(
104 kDefaultSearchProviderDataPrefName,
105 user_prefs::PrefRegistrySyncable::UNSYNCABLE_PREF);
106 }
107
108 // static
AddPrefValueToMap(base::DictionaryValue * value,PrefValueMap * pref_value_map)109 void DefaultSearchManager::AddPrefValueToMap(base::DictionaryValue* value,
110 PrefValueMap* pref_value_map) {
111 pref_value_map->SetValue(kDefaultSearchProviderDataPrefName, value);
112 }
113
114 // static
SetFallbackSearchEnginesDisabledForTesting(bool disabled)115 void DefaultSearchManager::SetFallbackSearchEnginesDisabledForTesting(
116 bool disabled) {
117 g_fallback_search_engines_disabled = disabled;
118 }
119
GetDefaultSearchEngine(Source * source) const120 TemplateURLData* DefaultSearchManager::GetDefaultSearchEngine(
121 Source* source) const {
122 if (default_search_controlled_by_policy_) {
123 if (source)
124 *source = FROM_POLICY;
125 return prefs_default_search_.get();
126 }
127 if (extension_default_search_) {
128 if (source)
129 *source = FROM_EXTENSION;
130 return extension_default_search_.get();
131 }
132 if (prefs_default_search_) {
133 if (source)
134 *source = FROM_USER;
135 return prefs_default_search_.get();
136 }
137
138 if (source)
139 *source = FROM_FALLBACK;
140 return g_fallback_search_engines_disabled ?
141 NULL : fallback_default_search_.get();
142 }
143
144 DefaultSearchManager::Source
GetDefaultSearchEngineSource() const145 DefaultSearchManager::GetDefaultSearchEngineSource() const {
146 Source source;
147 GetDefaultSearchEngine(&source);
148 return source;
149 }
150
SetUserSelectedDefaultSearchEngine(const TemplateURLData & data)151 void DefaultSearchManager::SetUserSelectedDefaultSearchEngine(
152 const TemplateURLData& data) {
153 if (!pref_service_) {
154 prefs_default_search_.reset(new TemplateURLData(data));
155 MergePrefsDataWithPrepopulated();
156 NotifyObserver();
157 return;
158 }
159
160 base::DictionaryValue url_dict;
161 url_dict.SetString(kID, base::Int64ToString(data.id));
162 url_dict.SetString(kShortName, data.short_name);
163 url_dict.SetString(kKeyword, data.keyword());
164 url_dict.SetInteger(kPrepopulateID, data.prepopulate_id);
165 url_dict.SetString(kSyncGUID, data.sync_guid);
166
167 url_dict.SetString(kURL, data.url());
168 url_dict.SetString(kSuggestionsURL, data.suggestions_url);
169 url_dict.SetString(kInstantURL, data.instant_url);
170 url_dict.SetString(kImageURL, data.image_url);
171 url_dict.SetString(kNewTabURL, data.new_tab_url);
172 url_dict.SetString(kFaviconURL, data.favicon_url.spec());
173 url_dict.SetString(kOriginatingURL, data.originating_url.spec());
174
175 url_dict.SetString(kSearchURLPostParams, data.search_url_post_params);
176 url_dict.SetString(kSuggestionsURLPostParams,
177 data.suggestions_url_post_params);
178 url_dict.SetString(kInstantURLPostParams, data.instant_url_post_params);
179 url_dict.SetString(kImageURLPostParams, data.image_url_post_params);
180
181 url_dict.SetBoolean(kSafeForAutoReplace, data.safe_for_autoreplace);
182
183 url_dict.SetString(kDateCreated,
184 base::Int64ToString(data.date_created.ToInternalValue()));
185 url_dict.SetString(kLastModified,
186 base::Int64ToString(data.last_modified.ToInternalValue()));
187 url_dict.SetInteger(kUsageCount, data.usage_count);
188
189 scoped_ptr<base::ListValue> alternate_urls(new base::ListValue);
190 for (std::vector<std::string>::const_iterator it =
191 data.alternate_urls.begin();
192 it != data.alternate_urls.end(); ++it) {
193 alternate_urls->AppendString(*it);
194 }
195 url_dict.Set(kAlternateURLs, alternate_urls.release());
196
197 scoped_ptr<base::ListValue> encodings(new base::ListValue);
198 for (std::vector<std::string>::const_iterator it =
199 data.input_encodings.begin();
200 it != data.input_encodings.end(); ++it) {
201 encodings->AppendString(*it);
202 }
203 url_dict.Set(kInputEncodings, encodings.release());
204
205 url_dict.SetString(kSearchTermsReplacementKey,
206 data.search_terms_replacement_key);
207
208 url_dict.SetBoolean(kCreatedByPolicy, data.created_by_policy);
209
210 pref_service_->Set(kDefaultSearchProviderDataPrefName, url_dict);
211 }
212
SetExtensionControlledDefaultSearchEngine(const TemplateURLData & data)213 void DefaultSearchManager::SetExtensionControlledDefaultSearchEngine(
214 const TemplateURLData& data) {
215 extension_default_search_.reset(new TemplateURLData(data));
216 if (GetDefaultSearchEngineSource() == FROM_EXTENSION)
217 NotifyObserver();
218 }
219
ClearExtensionControlledDefaultSearchEngine()220 void DefaultSearchManager::ClearExtensionControlledDefaultSearchEngine() {
221 Source old_source = GetDefaultSearchEngineSource();
222 extension_default_search_.reset();
223 if (old_source == FROM_EXTENSION)
224 NotifyObserver();
225 }
226
ClearUserSelectedDefaultSearchEngine()227 void DefaultSearchManager::ClearUserSelectedDefaultSearchEngine() {
228 if (pref_service_) {
229 pref_service_->ClearPref(kDefaultSearchProviderDataPrefName);
230 } else {
231 prefs_default_search_.reset();
232 NotifyObserver();
233 }
234 }
235
OnDefaultSearchPrefChanged()236 void DefaultSearchManager::OnDefaultSearchPrefChanged() {
237 Source source = GetDefaultSearchEngineSource();
238 LoadDefaultSearchEngineFromPrefs();
239
240 // If we were/are FROM_USER or FROM_POLICY the effective DSE may have changed.
241 if (source != FROM_USER && source != FROM_POLICY)
242 source = GetDefaultSearchEngineSource();
243 if (source == FROM_USER || source == FROM_POLICY)
244 NotifyObserver();
245 }
246
OnOverridesPrefChanged()247 void DefaultSearchManager::OnOverridesPrefChanged() {
248 LoadPrepopulatedDefaultSearch();
249
250 TemplateURLData* effective_data = GetDefaultSearchEngine(NULL);
251 if (effective_data && effective_data->prepopulate_id) {
252 // A user-selected, policy-selected or fallback pre-populated engine is
253 // active and may have changed with this event.
254 NotifyObserver();
255 }
256 }
257
MergePrefsDataWithPrepopulated()258 void DefaultSearchManager::MergePrefsDataWithPrepopulated() {
259 if (!prefs_default_search_ || !prefs_default_search_->prepopulate_id)
260 return;
261
262 size_t default_search_index;
263 ScopedVector<TemplateURLData> prepopulated_urls =
264 TemplateURLPrepopulateData::GetPrepopulatedEngines(pref_service_,
265 &default_search_index);
266
267 for (size_t i = 0; i < prepopulated_urls.size(); ++i) {
268 if (prepopulated_urls[i]->prepopulate_id ==
269 prefs_default_search_->prepopulate_id) {
270 if (!prefs_default_search_->safe_for_autoreplace) {
271 prepopulated_urls[i]->safe_for_autoreplace = false;
272 prepopulated_urls[i]->SetKeyword(prefs_default_search_->keyword());
273 prepopulated_urls[i]->short_name = prefs_default_search_->short_name;
274 }
275 prepopulated_urls[i]->id = prefs_default_search_->id;
276 prepopulated_urls[i]->sync_guid = prefs_default_search_->sync_guid;
277 prepopulated_urls[i]->date_created = prefs_default_search_->date_created;
278 prepopulated_urls[i]->last_modified =
279 prefs_default_search_->last_modified;
280 prefs_default_search_.reset(prepopulated_urls[i]);
281 prepopulated_urls.weak_erase(prepopulated_urls.begin() + i);
282 return;
283 }
284 }
285 }
286
LoadDefaultSearchEngineFromPrefs()287 void DefaultSearchManager::LoadDefaultSearchEngineFromPrefs() {
288 if (!pref_service_)
289 return;
290
291 prefs_default_search_.reset();
292 const PrefService::Preference* pref =
293 pref_service_->FindPreference(kDefaultSearchProviderDataPrefName);
294 DCHECK(pref);
295 default_search_controlled_by_policy_ = pref->IsManaged();
296
297 const base::DictionaryValue* url_dict =
298 pref_service_->GetDictionary(kDefaultSearchProviderDataPrefName);
299 if (url_dict->empty())
300 return;
301
302 if (default_search_controlled_by_policy_) {
303 bool disabled_by_policy = false;
304 if (url_dict->GetBoolean(kDisabledByPolicy, &disabled_by_policy) &&
305 disabled_by_policy)
306 return;
307 }
308
309 std::string search_url;
310 base::string16 keyword;
311 url_dict->GetString(kURL, &search_url);
312 url_dict->GetString(kKeyword, &keyword);
313 if (search_url.empty() || keyword.empty())
314 return;
315
316 prefs_default_search_.reset(new TemplateURLData);
317 prefs_default_search_->SetKeyword(keyword);
318 prefs_default_search_->SetURL(search_url);
319
320 std::string id;
321 url_dict->GetString(kID, &id);
322 base::StringToInt64(id, &prefs_default_search_->id);
323 url_dict->GetString(kShortName, &prefs_default_search_->short_name);
324 url_dict->GetInteger(kPrepopulateID, &prefs_default_search_->prepopulate_id);
325 url_dict->GetString(kSyncGUID, &prefs_default_search_->sync_guid);
326
327 url_dict->GetString(kSuggestionsURL, &prefs_default_search_->suggestions_url);
328 url_dict->GetString(kInstantURL, &prefs_default_search_->instant_url);
329 url_dict->GetString(kImageURL, &prefs_default_search_->image_url);
330 url_dict->GetString(kNewTabURL, &prefs_default_search_->new_tab_url);
331
332 std::string favicon_url;
333 std::string originating_url;
334 url_dict->GetString(kFaviconURL, &favicon_url);
335 url_dict->GetString(kOriginatingURL, &originating_url);
336 prefs_default_search_->favicon_url = GURL(favicon_url);
337 prefs_default_search_->originating_url = GURL(originating_url);
338
339 url_dict->GetString(kSearchURLPostParams,
340 &prefs_default_search_->search_url_post_params);
341 url_dict->GetString(kSuggestionsURLPostParams,
342 &prefs_default_search_->suggestions_url_post_params);
343 url_dict->GetString(kInstantURLPostParams,
344 &prefs_default_search_->instant_url_post_params);
345 url_dict->GetString(kImageURLPostParams,
346 &prefs_default_search_->image_url_post_params);
347
348 url_dict->GetBoolean(kSafeForAutoReplace,
349 &prefs_default_search_->safe_for_autoreplace);
350
351 std::string date_created_str;
352 std::string last_modified_str;
353 url_dict->GetString(kDateCreated, &date_created_str);
354 url_dict->GetString(kLastModified, &last_modified_str);
355
356 int64 date_created = 0;
357 if (base::StringToInt64(date_created_str, &date_created)) {
358 prefs_default_search_->date_created =
359 base::Time::FromInternalValue(date_created);
360 }
361
362 int64 last_modified = 0;
363 if (base::StringToInt64(date_created_str, &last_modified)) {
364 prefs_default_search_->last_modified =
365 base::Time::FromInternalValue(last_modified);
366 }
367
368 url_dict->GetInteger(kUsageCount, &prefs_default_search_->usage_count);
369
370 const base::ListValue* alternate_urls = NULL;
371 if (url_dict->GetList(kAlternateURLs, &alternate_urls)) {
372 for (base::ListValue::const_iterator it = alternate_urls->begin();
373 it != alternate_urls->end();
374 ++it) {
375 std::string alternate_url;
376 if ((*it)->GetAsString(&alternate_url))
377 prefs_default_search_->alternate_urls.push_back(alternate_url);
378 }
379 }
380
381 const base::ListValue* encodings = NULL;
382 if (url_dict->GetList(kInputEncodings, &encodings)) {
383 for (base::ListValue::const_iterator it = encodings->begin();
384 it != encodings->end();
385 ++it) {
386 std::string encoding;
387 if ((*it)->GetAsString(&encoding))
388 prefs_default_search_->input_encodings.push_back(encoding);
389 }
390 }
391
392 url_dict->GetString(kSearchTermsReplacementKey,
393 &prefs_default_search_->search_terms_replacement_key);
394
395 url_dict->GetBoolean(kCreatedByPolicy,
396 &prefs_default_search_->created_by_policy);
397
398 prefs_default_search_->show_in_default_list = true;
399 MergePrefsDataWithPrepopulated();
400 }
401
LoadPrepopulatedDefaultSearch()402 void DefaultSearchManager::LoadPrepopulatedDefaultSearch() {
403 scoped_ptr<TemplateURLData> data =
404 TemplateURLPrepopulateData::GetPrepopulatedDefaultSearch(pref_service_);
405 fallback_default_search_ = data.Pass();
406 MergePrefsDataWithPrepopulated();
407 }
408
NotifyObserver()409 void DefaultSearchManager::NotifyObserver() {
410 if (!change_observer_.is_null()) {
411 Source source = FROM_FALLBACK;
412 TemplateURLData* data = GetDefaultSearchEngine(&source);
413 change_observer_.Run(data, source);
414 }
415 }
416