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

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..a0c7f52c2c4efa5db38abc87a7085ca17c5905bb 100644
--- a/chrome/browser/android/ntp/popular_sites.cc
+++ b/chrome/browser/android/ntp/popular_sites.cc
@@ -11,25 +11,27 @@
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/json/json_reader.h"
-#include "base/path_service.h"
#include "base/strings/string_util.h"
#include "base/strings/stringprintf.h"
#include "base/task_runner_util.h"
#include "base/time/time.h"
#include "base/values.h"
-#include "chrome/common/chrome_paths.h"
#include "components/google/core/browser/google_util.h"
#include "components/ntp_tiles/pref_names.h"
#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 +125,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>> ParseJsonFile(
Marc Treib 2016/05/10 08:32:43 Just ParseJson now? Not a file anymore at this poi
sfiera 2016/05/11 09:00:24 Done.
+ const std::string& json) {
std::unique_ptr<base::Value> value =
base::JSONReader::Read(json, base::JSON_ALLOW_TRAILING_COMMAS);
base::ListValue* list;
@@ -170,6 +160,18 @@ 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?
Marc Treib 2016/05/10 08:32:43 Not that I'm aware.
sfiera 2016/05/11 09:00:24 Well.
+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);
+}
+
} // namespace
PopularSites::Site::Site(const base::string16& title,
@@ -191,6 +193,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 +201,7 @@ PopularSites::PopularSites(PrefService* prefs,
: PopularSites(prefs,
template_url_service,
download_context,
+ directory,
GetCountryToUse(prefs,
template_url_service,
variations_service,
@@ -210,11 +214,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,6 +253,7 @@ 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,
@@ -255,7 +262,9 @@ PopularSites::PopularSites(PrefService* prefs,
: callback_(callback),
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),
@@ -275,9 +284,18 @@ PopularSites::PopularSites(PrefService* prefs,
(time_since_last_download > redownload_interval) || country_changed ||
version_changed;
+ if (local_path_.empty()) {
+ BrowserThread::GetBlockingPool()
+ ->GetTaskRunnerWithShutdownBehavior(
+ base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)
+ ->PostTask(FROM_HERE, base::Bind(callback_, false));
Marc Treib 2016/05/10 08:32:43 Why are you posting the callback to another thread
sfiera 2016/05/11 09:00:24 I had thought that it was supposed to run on the b
Marc Treib 2016/05/11 10:20:28 Acknowledged.
+ return;
+ }
+
+ is_fallback_ = false;
Marc Treib 2016/05/10 08:32:42 Initialize this in the initializer list above? I d
sfiera 2016/05/11 09:00:24 Done.
FetchPopularSites(
override_url.is_valid() ? override_url : GetPopularSitesURL(),
- should_redownload_if_exists, false /* is_fallback */);
+ should_redownload_if_exists);
}
GURL PopularSites::GetPopularSitesURL() const {
@@ -286,53 +304,117 @@ 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::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::FetchPopularSites(const GURL& url, bool force_download) {
Marc Treib 2016/05/10 08:32:42 Split this into two methods, since the force vs no
sfiera 2016/05/11 09:00:24 I've inlined it above and kept only the actual fet
+ if (force_download) {
+ 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();
+ } else {
+ base::PostTaskAndReplyWithResult(
+ BrowserThread::GetBlockingPool()
+ ->GetTaskRunnerWithShutdownBehavior(
+ base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)
+ .get(),
Marc Treib 2016/05/10 08:32:43 IMO these four lines are now repeated often enough
sfiera 2016/05/11 09:00:24 Did one further.
+ FROM_HERE, base::Bind(&base::PathExists, local_path_),
+ base::Bind(&PopularSites::OnFileExistsCheckDone,
+ weak_ptr_factory_.GetWeakPtr(), url));
}
}
-void PopularSites::ParseSiteList(const base::FilePath& path) {
+void PopularSites::OnDownloadFailed() {
+ if (!is_fallback_) {
+ DLOG(WARNING) << "Download country site list failed";
+ is_fallback_ = true;
+ 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 */);
+ } else {
+ DLOG(WARNING) << "Download fallback site list failed";
+ callback_.Run(false);
+ }
+}
+
+void PopularSites::OnFileExistsCheckDone(const GURL& url, bool exists) {
+ if (exists) {
+ std::string json;
+ if (base::ReadFileToString(local_path_, &json)) {
Marc Treib 2016/05/10 08:32:43 This runs on the UI thread, right? That thread isn
sfiera 2016/05/10 08:44:51 I should have said up front: I have no real idea w
Marc Treib 2016/05/10 09:04:07 Rule of thumb: We're on the UI thread. :D DCHECK_C
sfiera 2016/05/11 09:00:24 Added it to the constructor. Should I add a commen
Marc Treib 2016/05/11 10:20:28 Adding a comment to the header is definitely appre
+ ParseSiteList(json);
+ } else {
+ // TODO(sfiera): remove and retry?
+ DLOG(WARNING) << "Failed reading file";
+ callback_.Run(false);
+ }
+ } else {
+ FetchPopularSites(url, true /* force_download */);
+ }
+}
+
+void PopularSites::OnURLFetchComplete(const net::URLFetcher* source) {
+ DCHECK_EQ(fetcher_.get(), source);
+ fetcher_.reset();
+
+ 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) {
+ base::PostTaskAndReplyWithResult(
+ BrowserThread::GetBlockingPool()
+ ->GetTaskRunnerWithShutdownBehavior(
+ base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)
+ .get(),
+ 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::OnFileWriteDone(const std::string& json, bool success) {
+ if (success) {
+ OnHaveNewFile(json);
+ } else {
+ DLOG(WARNING) << "could not write file to "
Marc Treib 2016/05/10 08:32:43 nitty nit: Start with a capital letter
sfiera 2016/05/11 09:00:24 Done.
+ << local_path_.LossyDisplayName();
+ OnDownloadFailed();
+ }
+}
+
+void PopularSites::OnHaveNewFile(const std::string& json) {
+ prefs_->SetInt64(kPopularSitesLastDownloadPref,
+ base::Time::Now().ToInternalValue());
+ prefs_->SetString(kPopularSitesCountryPref, pending_country_);
+ prefs_->SetString(kPopularSitesVersionPref, pending_version_);
+ ParseSiteList(json);
+}
+
+void PopularSites::ParseSiteList(const std::string& json) {
base::PostTaskAndReplyWithResult(
BrowserThread::GetBlockingPool()
->GetTaskRunnerWithShutdownBehavior(
base::SequencedWorkerPool::CONTINUE_ON_SHUTDOWN)
.get(),
- FROM_HERE, base::Bind(&ReadAndParseJsonFile, path),
+ FROM_HERE, base::Bind(&ParseJsonFile, json),
base::Bind(&PopularSites::OnJsonParsed, weak_ptr_factory_.GetWeakPtr()));
}

Powered by Google App Engine
This is Rietveld 408576698