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

Unified Diff: chrome/browser/android/ntp/popular_sites.cc

Issue 1957313003: Remove PopularSites' dependencies on //chrome/.... (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 side-by-side diff with in-line comments
Download patch
Index: chrome/browser/android/ntp/popular_sites.cc
diff --git a/chrome/browser/android/ntp/popular_sites.cc b/chrome/browser/android/ntp/popular_sites.cc
index e33ac30575519c74a3e9d6d095d7f0b6bf8b96df..1706c1a7151c0916227df1c367790b1b5eee7bfb 100644
--- a/chrome/browser/android/ntp/popular_sites.cc
+++ b/chrome/browser/android/ntp/popular_sites.cc
@@ -23,13 +23,17 @@
#include "components/ntp_tiles/switches.h"
#include "components/pref_registry/pref_registry_syncable.h"
#include "components/prefs/pref_service.h"
+#include "components/safe_json/json_sanitizer.h"
#include "components/search_engines/search_engine_type.h"
#include "components/search_engines/template_url_prepopulate_data.h"
#include "components/search_engines/template_url_service.h"
#include "components/variations/service/variations_service.h"
#include "content/public/browser/browser_thread.h"
+#include "net/base/load_flags.h"
+#include "net/http/http_status_code.h"
using content::BrowserThread;
+using net::URLFetcher;
using variations::VariationsService;
namespace {
@@ -123,20 +127,8 @@ std::string GetVersionToUse(const PrefService* prefs,
return version;
}
-base::FilePath GetPopularSitesPath() {
- base::FilePath dir;
- PathService::Get(chrome::DIR_USER_DATA, &dir);
- return dir.AppendASCII(kPopularSitesLocalFilename);
-}
-
-std::unique_ptr<std::vector<PopularSites::Site>> ReadAndParseJsonFile(
- const base::FilePath& path) {
- std::string json;
- if (!base::ReadFileToString(path, &json)) {
- DLOG(WARNING) << "Failed reading file";
- return nullptr;
- }
-
+std::unique_ptr<std::vector<PopularSites::Site>> ParseJson(
+ const std::string& json) {
std::unique_ptr<base::Value> value =
base::JSONReader::Read(json, base::JSON_ALLOW_TRAILING_COMMAS);
base::ListValue* list;
@@ -170,8 +162,44 @@ std::unique_ptr<std::vector<PopularSites::Site>> ReadAndParseJsonFile(
return sites;
}
+// Write |data| to a temporary file, then move it to |path|, thereby ensuring
+// that a partial file cannot be written.
+//
+// TODO(sfiera): is there some helper for this somewhere?
Bernhard Bauer 2016/05/12 12:24:24 Yes :) base::ImportantFileWriter.
sfiera 2016/05/12 14:03:05 Oh, nice, this is an important file now. Done. (G
+bool WriteStringToFileAtomic(const std::string& data,
+ const base::FilePath& path) {
+ base::FilePath temporary_path;
+ return base::CreateTemporaryFile(&temporary_path) &&
+ base::WriteFile(temporary_path, data.data(), data.size()) &&
+ base::Move(temporary_path, path);
+}
+
+// Run |call| on the thread pool for blocking operations, then call |done| with
+// its result on the original thread.
Bernhard Bauer 2016/05/12 12:24:24 The common way to do this is to get a single Seque
sfiera 2016/05/12 14:03:05 I grabbed a TaskRunner instead of a SequencedTaskR
+template <typename T>
+void RunBlockingTaskAndReply(const tracked_objects::Location& from_here,
+ const base::Callback<T()>& call,
+ const base::Callback<void(T)>& done) {
+ base::PostTaskAndReplyWithResult(
+ BrowserThread::GetBlockingPool()
+ ->GetTaskRunnerWithShutdownBehavior(
+ base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)
+ .get(),
+ from_here, call, done);
+}
+
} // namespace
+namespace ntp_tiles {
+
+base::FilePath GetPopularSitesDirectory() {
+ base::FilePath dir;
+ PathService::Get(chrome::DIR_USER_DATA, &dir);
+ return dir; // empty if PathService::Get() failed.
+}
+
+} // namespace ntp_tiles
+
PopularSites::Site::Site(const base::string16& title,
const GURL& url,
const GURL& favicon_url,
@@ -191,6 +219,7 @@ PopularSites::PopularSites(PrefService* prefs,
const TemplateURLService* template_url_service,
VariationsService* variations_service,
net::URLRequestContextGetter* download_context,
+ const base::FilePath& directory,
const std::string& variation_param_country,
const std::string& variation_param_version,
bool force_download,
@@ -198,6 +227,7 @@ PopularSites::PopularSites(PrefService* prefs,
: PopularSites(prefs,
template_url_service,
download_context,
+ directory,
GetCountryToUse(prefs,
template_url_service,
variations_service,
@@ -210,11 +240,13 @@ PopularSites::PopularSites(PrefService* prefs,
PopularSites::PopularSites(PrefService* prefs,
const TemplateURLService* template_url_service,
net::URLRequestContextGetter* download_context,
+ const base::FilePath& directory,
const GURL& url,
const FinishedCallback& callback)
: PopularSites(prefs,
template_url_service,
download_context,
+ directory,
std::string(),
std::string(),
url,
@@ -247,19 +279,24 @@ void PopularSites::RegisterProfilePrefs(
PopularSites::PopularSites(PrefService* prefs,
const TemplateURLService* template_url_service,
net::URLRequestContextGetter* download_context,
+ const base::FilePath& directory,
const std::string& country,
const std::string& version,
const GURL& override_url,
bool force_download,
const FinishedCallback& callback)
: callback_(callback),
+ is_fallback_(false),
pending_country_(country),
pending_version_(version),
- local_path_(GetPopularSitesPath()),
+ local_path_(directory.empty()
+ ? base::FilePath()
+ : directory.AppendASCII(kPopularSitesLocalFilename)),
prefs_(prefs),
template_url_service_(template_url_service),
download_context_(download_context),
weak_ptr_factory_(this) {
+ DCHECK_CURRENTLY_ON(BrowserThread::UI);
const base::Time last_download_time = base::Time::FromInternalValue(
prefs_->GetInt64(kPopularSitesLastDownloadPref));
const base::TimeDelta time_since_last_download =
@@ -270,14 +307,31 @@ PopularSites::PopularSites(PrefService* prefs,
const bool country_changed = GetCountry() != pending_country_;
const bool version_changed = GetVersion() != pending_version_;
- const bool should_redownload_if_exists =
- force_download || download_time_is_future ||
+ const GURL url =
+ override_url.is_valid() ? override_url : GetPopularSitesURL();
+
+ // No valid path to save to. Immediately post failure.
+ if (local_path_.empty()) {
+ BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
+ base::Bind(callback_, false));
+ return;
+ }
+
+ // Download forced, or we need to download a new file.
+ if (force_download || download_time_is_future ||
(time_since_last_download > redownload_interval) || country_changed ||
- version_changed;
+ version_changed) {
+ FetchPopularSites(url);
+ return;
+ }
- FetchPopularSites(
- override_url.is_valid() ? override_url : GetPopularSitesURL(),
- should_redownload_if_exists, false /* is_fallback */);
+ std::unique_ptr<std::string> file_data(new std::string);
+ std::string* file_data_ptr = file_data.get();
+ RunBlockingTaskAndReply(
+ FROM_HERE,
+ base::Bind(&base::ReadFileToString, local_path_, file_data_ptr),
+ base::Bind(&PopularSites::OnReadFileDone, weak_ptr_factory_.GetWeakPtr(),
+ url, base::Passed(std::move(file_data))));
}
GURL PopularSites::GetPopularSitesURL() const {
@@ -286,53 +340,75 @@ GURL PopularSites::GetPopularSitesURL() const {
pending_version_.c_str()));
}
-void PopularSites::FetchPopularSites(const GURL& url,
- bool force_download,
- bool is_fallback) {
- downloader_.reset(new FileDownloader(
- url, local_path_, force_download, download_context_,
- base::Bind(&PopularSites::OnDownloadDone, base::Unretained(this),
- is_fallback)));
+void PopularSites::OnReadFileDone(const GURL& url,
+ std::unique_ptr<std::string> data,
+ bool success) {
+ if (success) {
+ ParseSiteList(*data);
+ } else {
+ // File didn't exist, or couldn't be read for some other reason.
+ FetchPopularSites(url);
+ }
+}
+
+void PopularSites::FetchPopularSites(const GURL& url) {
+ fetcher_ = URLFetcher::Create(url, URLFetcher::GET, this);
+ fetcher_->SetRequestContext(download_context_);
+ fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
+ net::LOAD_DO_NOT_SAVE_COOKIES);
+ fetcher_->SetAutomaticallyRetryOnNetworkChanges(1);
+ fetcher_->Start();
+}
+
+void PopularSites::OnURLFetchComplete(const net::URLFetcher* source) {
+ DCHECK_EQ(fetcher_.get(), source);
+ std::unique_ptr<net::URLFetcher> free_fetcher = std::move(fetcher_);
+
+ std::string sketchy_json;
+ if (!(source->GetStatus().is_success() &&
+ source->GetResponseCode() == net::HTTP_OK &&
+ source->GetResponseAsString(&sketchy_json))) {
+ OnDownloadFailed();
+ return;
+ }
+
+ safe_json::JsonSanitizer::Sanitize(
+ sketchy_json, base::Bind(&PopularSites::OnJsonSanitized,
+ weak_ptr_factory_.GetWeakPtr()),
+ base::Bind(&PopularSites::OnJsonSanitizationFailed,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void PopularSites::OnJsonSanitized(const std::string& valid_minified_json) {
+ RunBlockingTaskAndReply(
+ FROM_HERE,
+ base::Bind(&WriteStringToFileAtomic, valid_minified_json, local_path_),
+ base::Bind(&PopularSites::OnFileWriteDone, weak_ptr_factory_.GetWeakPtr(),
+ valid_minified_json));
+}
+
+void PopularSites::OnJsonSanitizationFailed(const std::string& error_message) {
+ DLOG(WARNING) << "JSON sanitization failed: " << error_message;
+ OnDownloadFailed();
}
-void PopularSites::OnDownloadDone(bool is_fallback,
- FileDownloader::Result result) {
- downloader_.reset();
- switch (result) {
- case FileDownloader::DOWNLOADED:
- prefs_->SetInt64(kPopularSitesLastDownloadPref,
- base::Time::Now().ToInternalValue());
- prefs_->SetString(kPopularSitesCountryPref, pending_country_);
- prefs_->SetString(kPopularSitesVersionPref, pending_version_);
- ParseSiteList(local_path_);
- break;
- case FileDownloader::EXISTS:
- ParseSiteList(local_path_);
- break;
- case FileDownloader::FAILED:
- if (!is_fallback) {
- DLOG(WARNING) << "Download country site list failed";
- pending_country_ = kPopularSitesDefaultCountryCode;
- pending_version_ = kPopularSitesDefaultVersion;
- // It is fine to force the download as Fallback is only triggered after
- // a failed download.
- FetchPopularSites(GetPopularSitesURL(), true /* force_download */,
- true /* is_fallback */);
- } else {
- DLOG(WARNING) << "Download fallback site list failed";
- callback_.Run(false);
- }
- break;
+void PopularSites::OnFileWriteDone(const std::string& json, bool success) {
+ if (success) {
+ prefs_->SetInt64(kPopularSitesLastDownloadPref,
+ base::Time::Now().ToInternalValue());
+ prefs_->SetString(kPopularSitesCountryPref, pending_country_);
+ prefs_->SetString(kPopularSitesVersionPref, pending_version_);
+ ParseSiteList(json);
+ } else {
+ DLOG(WARNING) << "Could not write file to "
+ << local_path_.LossyDisplayName();
+ OnDownloadFailed();
}
}
-void PopularSites::ParseSiteList(const base::FilePath& path) {
- base::PostTaskAndReplyWithResult(
- BrowserThread::GetBlockingPool()
- ->GetTaskRunnerWithShutdownBehavior(
- base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)
- .get(),
- FROM_HERE, base::Bind(&ReadAndParseJsonFile, path),
+void PopularSites::ParseSiteList(const std::string& json) {
+ RunBlockingTaskAndReply(
+ FROM_HERE, base::Bind(&ParseJson, json),
base::Bind(&PopularSites::OnJsonParsed, weak_ptr_factory_.GetWeakPtr()));
}
@@ -343,3 +419,16 @@ void PopularSites::OnJsonParsed(std::unique_ptr<std::vector<Site>> sites) {
sites_.clear();
callback_.Run(!!sites);
}
+
+void PopularSites::OnDownloadFailed() {
+ if (!is_fallback_) {
+ DLOG(WARNING) << "Download country site list failed";
+ is_fallback_ = true;
+ pending_country_ = kPopularSitesDefaultCountryCode;
+ pending_version_ = kPopularSitesDefaultVersion;
+ FetchPopularSites(GetPopularSitesURL());
+ } else {
+ DLOG(WARNING) << "Download fallback site list failed";
+ callback_.Run(false);
+ }
+}

Powered by Google App Engine
This is Rietveld 408576698