Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1)

Side by Side Diff: chrome/browser/android/ntp/popular_sites.cc

Issue 1983063002: Move classes to //components/ntp_tiles. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright 2015 The Chromium Authors. All rights reserved. 1 // Copyright 2015 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/android/ntp/popular_sites.h" 5 #include "chrome/browser/android/ntp/popular_sites.h"
6 6
7 #include <stddef.h>
8
9 #include "base/bind.h"
10 #include "base/command_line.h"
11 #include "base/files/file_path.h"
12 #include "base/files/file_util.h"
13 #include "base/files/important_file_writer.h"
14 #include "base/json/json_reader.h"
15 #include "base/path_service.h" 7 #include "base/path_service.h"
16 #include "base/strings/string_util.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/task_runner_util.h"
19 #include "base/time/time.h"
20 #include "base/values.h"
21 #include "chrome/common/chrome_paths.h" 8 #include "chrome/common/chrome_paths.h"
22 #include "components/google/core/browser/google_util.h"
23 #include "components/ntp_tiles/pref_names.h"
24 #include "components/ntp_tiles/switches.h"
25 #include "components/pref_registry/pref_registry_syncable.h"
26 #include "components/prefs/pref_service.h"
27 #include "components/safe_json/json_sanitizer.h"
28 #include "components/search_engines/search_engine_type.h"
29 #include "components/search_engines/template_url_prepopulate_data.h"
30 #include "components/search_engines/template_url_service.h"
31 #include "components/variations/service/variations_service.h"
32 #include "content/public/browser/browser_thread.h"
33 #include "net/base/load_flags.h"
34 #include "net/http/http_status_code.h"
35
36 using content::BrowserThread;
37 using net::URLFetcher;
38 using variations::VariationsService;
39
40 namespace {
41
42 const char kPopularSitesURLFormat[] =
43 "https://www.gstatic.com/chrome/ntp/suggested_sites_%s_%s.json";
44 const char kPopularSitesDefaultCountryCode[] = "DEFAULT";
45 const char kPopularSitesDefaultVersion[] = "5";
46 const char kPopularSitesLocalFilename[] = "suggested_sites.json";
47 const int kPopularSitesRedownloadIntervalHours = 24;
48
49 const char kPopularSitesLastDownloadPref[] = "popular_sites_last_download";
50 const char kPopularSitesCountryPref[] = "popular_sites_country";
51 const char kPopularSitesVersionPref[] = "popular_sites_version";
52
53 // Extract the country from the default search engine if the default search
54 // engine is Google.
55 std::string GetDefaultSearchEngineCountryCode(
56 const TemplateURLService* template_url_service) {
57 DCHECK(template_url_service);
58
59 base::CommandLine* cmd_line = base::CommandLine::ForCurrentProcess();
60 if (!cmd_line->HasSwitch(
61 ntp_tiles::switches::kEnableNTPSearchEngineCountryDetection))
62 return std::string();
63
64 const TemplateURL* default_provider =
65 template_url_service->GetDefaultSearchProvider();
66 // It's possible to not have a default provider in the case that the default
67 // search engine is defined by policy.
68 if (default_provider) {
69 bool is_google_search_engine =
70 TemplateURLPrepopulateData::GetEngineType(
71 *default_provider, template_url_service->search_terms_data()) ==
72 SearchEngineType::SEARCH_ENGINE_GOOGLE;
73
74 if (is_google_search_engine) {
75 GURL search_url = default_provider->GenerateSearchURL(
76 template_url_service->search_terms_data());
77 return google_util::GetGoogleCountryCode(search_url);
78 }
79 }
80
81 return std::string();
82 }
83
84 // Determine the country code to use. In order of precedence:
85 // - The explicit "override country" pref set by the user.
86 // - The country code from the field trial config (variation parameter).
87 // - The Google country code if Google is the default search engine (and the
88 // "--enable-ntp-search-engine-country-detection" switch is present).
89 // - The country provided by the VariationsService.
90 // - A default fallback.
91 std::string GetCountryToUse(const PrefService* prefs,
92 const TemplateURLService* template_url_service,
93 VariationsService* variations_service,
94 const std::string& variation_param_country) {
95 std::string country_code =
96 prefs->GetString(ntp_tiles::prefs::kPopularSitesOverrideCountry);
97
98 if (country_code.empty())
99 country_code = variation_param_country;
100
101 if (country_code.empty())
102 country_code = GetDefaultSearchEngineCountryCode(template_url_service);
103
104 if (country_code.empty() && variations_service)
105 country_code = variations_service->GetStoredPermanentCountry();
106
107 if (country_code.empty())
108 country_code = kPopularSitesDefaultCountryCode;
109
110 return base::ToUpperASCII(country_code);
111 }
112
113 // Determine the version to use. In order of precedence:
114 // - The explicit "override version" pref set by the user.
115 // - The version from the field trial config (variation parameter).
116 // - A default fallback.
117 std::string GetVersionToUse(const PrefService* prefs,
118 const std::string& variation_param_version) {
119 std::string version =
120 prefs->GetString(ntp_tiles::prefs::kPopularSitesOverrideVersion);
121
122 if (version.empty())
123 version = variation_param_version;
124
125 if (version.empty())
126 version = kPopularSitesDefaultVersion;
127
128 return version;
129 }
130
131 std::unique_ptr<std::vector<PopularSites::Site>> ParseJson(
132 const std::string& json) {
133 std::unique_ptr<base::Value> value =
134 base::JSONReader::Read(json, base::JSON_ALLOW_TRAILING_COMMAS);
135 base::ListValue* list;
136 if (!value || !value->GetAsList(&list)) {
137 DLOG(WARNING) << "Failed parsing json";
138 return nullptr;
139 }
140
141 std::unique_ptr<std::vector<PopularSites::Site>> sites(
142 new std::vector<PopularSites::Site>);
143 for (size_t i = 0; i < list->GetSize(); i++) {
144 base::DictionaryValue* item;
145 if (!list->GetDictionary(i, &item))
146 continue;
147 base::string16 title;
148 std::string url;
149 if (!item->GetString("title", &title) || !item->GetString("url", &url))
150 continue;
151 std::string favicon_url;
152 item->GetString("favicon_url", &favicon_url);
153 std::string thumbnail_url;
154 item->GetString("thumbnail_url", &thumbnail_url);
155 std::string large_icon_url;
156 item->GetString("large_icon_url", &large_icon_url);
157
158 sites->push_back(PopularSites::Site(title, GURL(url), GURL(favicon_url),
159 GURL(large_icon_url),
160 GURL(thumbnail_url)));
161 }
162
163 return sites;
164 }
165
166 } // namespace
167 9
168 base::FilePath ChromePopularSites::GetDirectory() { 10 base::FilePath ChromePopularSites::GetDirectory() {
169 base::FilePath dir; 11 base::FilePath dir;
170 PathService::Get(chrome::DIR_USER_DATA, &dir); 12 PathService::Get(chrome::DIR_USER_DATA, &dir);
171 return dir; // empty if PathService::Get() failed. 13 return dir; // empty if PathService::Get() failed.
172 } 14 }
173
174 PopularSites::Site::Site(const base::string16& title,
175 const GURL& url,
176 const GURL& favicon_url,
177 const GURL& large_icon_url,
178 const GURL& thumbnail_url)
179 : title(title),
180 url(url),
181 favicon_url(favicon_url),
182 large_icon_url(large_icon_url),
183 thumbnail_url(thumbnail_url) {}
184
185 PopularSites::Site::Site(const Site& other) = default;
186
187 PopularSites::Site::~Site() {}
188
189 PopularSites::PopularSites(PrefService* prefs,
190 const TemplateURLService* template_url_service,
191 VariationsService* variations_service,
192 net::URLRequestContextGetter* download_context,
193 const base::FilePath& directory,
194 const std::string& variation_param_country,
195 const std::string& variation_param_version,
196 bool force_download,
197 const FinishedCallback& callback)
198 : PopularSites(prefs,
199 template_url_service,
200 download_context,
201 directory,
202 GetCountryToUse(prefs,
203 template_url_service,
204 variations_service,
205 variation_param_country),
206 GetVersionToUse(prefs, variation_param_version),
207 GURL(),
208 force_download,
209 callback) {}
210
211 PopularSites::PopularSites(PrefService* prefs,
212 const TemplateURLService* template_url_service,
213 net::URLRequestContextGetter* download_context,
214 const base::FilePath& directory,
215 const GURL& url,
216 const FinishedCallback& callback)
217 : PopularSites(prefs,
218 template_url_service,
219 download_context,
220 directory,
221 std::string(),
222 std::string(),
223 url,
224 true,
225 callback) {}
226
227 PopularSites::~PopularSites() {}
228
229 std::string PopularSites::GetCountry() const {
230 return prefs_->GetString(kPopularSitesCountryPref);
231 }
232
233 std::string PopularSites::GetVersion() const {
234 return prefs_->GetString(kPopularSitesVersionPref);
235 }
236
237 // static
238 void PopularSites::RegisterProfilePrefs(
239 user_prefs::PrefRegistrySyncable* user_prefs) {
240 user_prefs->RegisterStringPref(ntp_tiles::prefs::kPopularSitesOverrideCountry,
241 std::string());
242 user_prefs->RegisterStringPref(ntp_tiles::prefs::kPopularSitesOverrideVersion,
243 std::string());
244
245 user_prefs->RegisterInt64Pref(kPopularSitesLastDownloadPref, 0);
246 user_prefs->RegisterStringPref(kPopularSitesCountryPref, std::string());
247 user_prefs->RegisterStringPref(kPopularSitesVersionPref, std::string());
248 }
249
250 PopularSites::PopularSites(PrefService* prefs,
251 const TemplateURLService* template_url_service,
252 net::URLRequestContextGetter* download_context,
253 const base::FilePath& directory,
254 const std::string& country,
255 const std::string& version,
256 const GURL& override_url,
257 bool force_download,
258 const FinishedCallback& callback)
259 : callback_(callback),
260 is_fallback_(false),
261 pending_country_(country),
262 pending_version_(version),
263 local_path_(directory.empty()
264 ? base::FilePath()
265 : directory.AppendASCII(kPopularSitesLocalFilename)),
266 prefs_(prefs),
267 template_url_service_(template_url_service),
268 download_context_(download_context),
269 runner_(
270 BrowserThread::GetBlockingPool()->GetTaskRunnerWithShutdownBehavior(
271 base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)),
272 weak_ptr_factory_(this) {
273 DCHECK_CURRENTLY_ON(BrowserThread::UI);
274 const base::Time last_download_time = base::Time::FromInternalValue(
275 prefs_->GetInt64(kPopularSitesLastDownloadPref));
276 const base::TimeDelta time_since_last_download =
277 base::Time::Now() - last_download_time;
278 const base::TimeDelta redownload_interval =
279 base::TimeDelta::FromHours(kPopularSitesRedownloadIntervalHours);
280 const bool download_time_is_future = base::Time::Now() < last_download_time;
281 const bool country_changed = GetCountry() != pending_country_;
282 const bool version_changed = GetVersion() != pending_version_;
283
284 const GURL url =
285 override_url.is_valid() ? override_url : GetPopularSitesURL();
286
287 // No valid path to save to. Immediately post failure.
288 if (local_path_.empty()) {
289 BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
290 base::Bind(callback_, false));
291 return;
292 }
293
294 // Download forced, or we need to download a new file.
295 if (force_download || download_time_is_future ||
296 (time_since_last_download > redownload_interval) || country_changed ||
297 version_changed) {
298 FetchPopularSites(url);
299 return;
300 }
301
302 std::unique_ptr<std::string> file_data(new std::string);
303 std::string* file_data_ptr = file_data.get();
304 base::PostTaskAndReplyWithResult(
305 runner_.get(), FROM_HERE,
306 base::Bind(&base::ReadFileToString, local_path_, file_data_ptr),
307 base::Bind(&PopularSites::OnReadFileDone, weak_ptr_factory_.GetWeakPtr(),
308 url, base::Passed(std::move(file_data))));
309 }
310
311 GURL PopularSites::GetPopularSitesURL() const {
312 return GURL(base::StringPrintf(kPopularSitesURLFormat,
313 pending_country_.c_str(),
314 pending_version_.c_str()));
315 }
316
317 void PopularSites::OnReadFileDone(const GURL& url,
318 std::unique_ptr<std::string> data,
319 bool success) {
320 if (success) {
321 ParseSiteList(*data);
322 } else {
323 // File didn't exist, or couldn't be read for some other reason.
324 FetchPopularSites(url);
325 }
326 }
327
328 void PopularSites::FetchPopularSites(const GURL& url) {
329 fetcher_ = URLFetcher::Create(url, URLFetcher::GET, this);
330 fetcher_->SetRequestContext(download_context_);
331 fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
332 net::LOAD_DO_NOT_SAVE_COOKIES);
333 fetcher_->SetAutomaticallyRetryOnNetworkChanges(1);
334 fetcher_->Start();
335 }
336
337 void PopularSites::OnURLFetchComplete(const net::URLFetcher* source) {
338 DCHECK_EQ(fetcher_.get(), source);
339 std::unique_ptr<net::URLFetcher> free_fetcher = std::move(fetcher_);
340
341 std::string sketchy_json;
342 if (!(source->GetStatus().is_success() &&
343 source->GetResponseCode() == net::HTTP_OK &&
344 source->GetResponseAsString(&sketchy_json))) {
345 OnDownloadFailed();
346 return;
347 }
348
349 safe_json::JsonSanitizer::Sanitize(
350 sketchy_json, base::Bind(&PopularSites::OnJsonSanitized,
351 weak_ptr_factory_.GetWeakPtr()),
352 base::Bind(&PopularSites::OnJsonSanitizationFailed,
353 weak_ptr_factory_.GetWeakPtr()));
354 }
355
356 void PopularSites::OnJsonSanitized(const std::string& valid_minified_json) {
357 base::PostTaskAndReplyWithResult(
358 runner_.get(), FROM_HERE,
359 base::Bind(&base::ImportantFileWriter::WriteFileAtomically, local_path_,
360 valid_minified_json),
361 base::Bind(&PopularSites::OnFileWriteDone, weak_ptr_factory_.GetWeakPtr(),
362 valid_minified_json));
363 }
364
365 void PopularSites::OnJsonSanitizationFailed(const std::string& error_message) {
366 DLOG(WARNING) << "JSON sanitization failed: " << error_message;
367 OnDownloadFailed();
368 }
369
370 void PopularSites::OnFileWriteDone(const std::string& json, bool success) {
371 if (success) {
372 prefs_->SetInt64(kPopularSitesLastDownloadPref,
373 base::Time::Now().ToInternalValue());
374 prefs_->SetString(kPopularSitesCountryPref, pending_country_);
375 prefs_->SetString(kPopularSitesVersionPref, pending_version_);
376 ParseSiteList(json);
377 } else {
378 DLOG(WARNING) << "Could not write file to "
379 << local_path_.LossyDisplayName();
380 OnDownloadFailed();
381 }
382 }
383
384 void PopularSites::ParseSiteList(const std::string& json) {
385 base::PostTaskAndReplyWithResult(
386 runner_.get(), FROM_HERE, base::Bind(&ParseJson, json),
387 base::Bind(&PopularSites::OnJsonParsed, weak_ptr_factory_.GetWeakPtr()));
388 }
389
390 void PopularSites::OnJsonParsed(std::unique_ptr<std::vector<Site>> sites) {
391 if (sites)
392 sites_.swap(*sites);
393 else
394 sites_.clear();
395 callback_.Run(!!sites);
396 }
397
398 void PopularSites::OnDownloadFailed() {
399 if (!is_fallback_) {
400 DLOG(WARNING) << "Download country site list failed";
401 is_fallback_ = true;
402 pending_country_ = kPopularSitesDefaultCountryCode;
403 pending_version_ = kPopularSitesDefaultVersion;
404 FetchPopularSites(GetPopularSitesURL());
405 } else {
406 DLOG(WARNING) << "Download fallback site list failed";
407 callback_.Run(false);
408 }
409 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698