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

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

Issue 2031603002: In PopularSites, parse (not sanitize) JSON safely. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 6 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
« no previous file with comments | « chrome/browser/android/ntp/popular_sites.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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> 7 #include <stddef.h>
8 8
9 #include "base/bind.h" 9 #include "base/bind.h"
10 #include "base/command_line.h" 10 #include "base/command_line.h"
11 #include "base/files/file_path.h" 11 #include "base/files/file_path.h"
12 #include "base/files/file_util.h" 12 #include "base/files/file_util.h"
13 #include "base/files/important_file_writer.h" 13 #include "base/files/important_file_writer.h"
14 #include "base/json/json_reader.h" 14 #include "base/json/json_reader.h"
15 #include "base/json/json_writer.h"
15 #include "base/path_service.h" 16 #include "base/path_service.h"
16 #include "base/strings/string_util.h" 17 #include "base/strings/string_util.h"
17 #include "base/strings/stringprintf.h" 18 #include "base/strings/stringprintf.h"
18 #include "base/task_runner_util.h" 19 #include "base/task_runner_util.h"
19 #include "base/time/time.h" 20 #include "base/time/time.h"
20 #include "base/values.h" 21 #include "base/values.h"
21 #include "chrome/common/chrome_paths.h" 22 #include "chrome/common/chrome_paths.h"
22 #include "components/google/core/browser/google_util.h" 23 #include "components/google/core/browser/google_util.h"
23 #include "components/ntp_tiles/pref_names.h" 24 #include "components/ntp_tiles/pref_names.h"
24 #include "components/ntp_tiles/switches.h" 25 #include "components/ntp_tiles/switches.h"
25 #include "components/pref_registry/pref_registry_syncable.h" 26 #include "components/pref_registry/pref_registry_syncable.h"
26 #include "components/prefs/pref_service.h" 27 #include "components/prefs/pref_service.h"
27 #include "components/safe_json/json_sanitizer.h" 28 #include "components/safe_json/safe_json_parser.h"
28 #include "components/search_engines/search_engine_type.h" 29 #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_prepopulate_data.h"
30 #include "components/search_engines/template_url_service.h" 31 #include "components/search_engines/template_url_service.h"
31 #include "components/variations/service/variations_service.h" 32 #include "components/variations/service/variations_service.h"
32 #include "net/base/load_flags.h" 33 #include "net/base/load_flags.h"
33 #include "net/http/http_status_code.h" 34 #include "net/http/http_status_code.h"
34 35
35 using net::URLFetcher; 36 using net::URLFetcher;
36 using variations::VariationsService; 37 using variations::VariationsService;
37 38
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
119 120
120 if (version.empty()) 121 if (version.empty())
121 version = variation_param_version; 122 version = variation_param_version;
122 123
123 if (version.empty()) 124 if (version.empty())
124 version = kPopularSitesDefaultVersion; 125 version = kPopularSitesDefaultVersion;
125 126
126 return version; 127 return version;
127 } 128 }
128 129
129 std::unique_ptr<std::vector<PopularSites::Site>> ParseJson( 130 // Must run on the blocking thread pool.
130 const std::string& json) { 131 bool WriteJsonToFile(const base::FilePath& local_path,
131 std::unique_ptr<base::Value> value = 132 const base::Value* json) {
132 base::JSONReader::Read(json, base::JSON_ALLOW_TRAILING_COMMAS); 133 std::string json_string;
133 base::ListValue* list; 134 return base::JSONWriter::Write(*json, &json_string) &&
134 if (!value || !value->GetAsList(&list)) { 135 base::ImportantFileWriter::WriteFileAtomically(local_path,
135 DLOG(WARNING) << "Failed parsing json"; 136 json_string);
136 return nullptr;
137 }
138
139 std::unique_ptr<std::vector<PopularSites::Site>> sites(
140 new std::vector<PopularSites::Site>);
141 for (size_t i = 0; i < list->GetSize(); i++) {
142 base::DictionaryValue* item;
143 if (!list->GetDictionary(i, &item))
144 continue;
145 base::string16 title;
146 std::string url;
147 if (!item->GetString("title", &title) || !item->GetString("url", &url))
148 continue;
149 std::string favicon_url;
150 item->GetString("favicon_url", &favicon_url);
151 std::string thumbnail_url;
152 item->GetString("thumbnail_url", &thumbnail_url);
153 std::string large_icon_url;
154 item->GetString("large_icon_url", &large_icon_url);
155
156 sites->push_back(PopularSites::Site(title, GURL(url), GURL(favicon_url),
157 GURL(large_icon_url),
158 GURL(thumbnail_url)));
159 }
160
161 return sites;
162 } 137 }
163 138
164 } // namespace 139 } // namespace
165 140
166 base::FilePath ChromePopularSites::GetDirectory() { 141 base::FilePath ChromePopularSites::GetDirectory() {
167 base::FilePath dir; 142 base::FilePath dir;
168 PathService::Get(chrome::DIR_USER_DATA, &dir); 143 PathService::Get(chrome::DIR_USER_DATA, &dir);
169 return dir; // empty if PathService::Get() failed. 144 return dir; // empty if PathService::Get() failed.
170 } 145 }
171 146
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 GURL PopularSites::GetPopularSitesURL() const { 285 GURL PopularSites::GetPopularSitesURL() const {
311 return GURL(base::StringPrintf(kPopularSitesURLFormat, 286 return GURL(base::StringPrintf(kPopularSitesURLFormat,
312 pending_country_.c_str(), 287 pending_country_.c_str(),
313 pending_version_.c_str())); 288 pending_version_.c_str()));
314 } 289 }
315 290
316 void PopularSites::OnReadFileDone(const GURL& url, 291 void PopularSites::OnReadFileDone(const GURL& url,
317 std::unique_ptr<std::string> data, 292 std::unique_ptr<std::string> data,
318 bool success) { 293 bool success) {
319 if (success) { 294 if (success) {
320 ParseSiteList(*data); 295 auto json = base::JSONReader::Read(*data, base::JSON_ALLOW_TRAILING_COMMAS);
296 if (json) {
297 ParseSiteList(std::move(json));
298 } else {
299 OnJsonParseFailed("previously-fetched JSON was no longer parseable");
300 }
321 } else { 301 } else {
322 // File didn't exist, or couldn't be read for some other reason. 302 // File didn't exist, or couldn't be read for some other reason.
323 FetchPopularSites(url); 303 FetchPopularSites(url);
324 } 304 }
325 } 305 }
326 306
327 void PopularSites::FetchPopularSites(const GURL& url) { 307 void PopularSites::FetchPopularSites(const GURL& url) {
328 fetcher_ = URLFetcher::Create(url, URLFetcher::GET, this); 308 fetcher_ = URLFetcher::Create(url, URLFetcher::GET, this);
329 fetcher_->SetRequestContext(download_context_); 309 fetcher_->SetRequestContext(download_context_);
330 fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | 310 fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
331 net::LOAD_DO_NOT_SAVE_COOKIES); 311 net::LOAD_DO_NOT_SAVE_COOKIES);
332 fetcher_->SetAutomaticallyRetryOnNetworkChanges(1); 312 fetcher_->SetAutomaticallyRetryOnNetworkChanges(1);
333 fetcher_->Start(); 313 fetcher_->Start();
334 } 314 }
335 315
336 void PopularSites::OnURLFetchComplete(const net::URLFetcher* source) { 316 void PopularSites::OnURLFetchComplete(const net::URLFetcher* source) {
337 DCHECK_EQ(fetcher_.get(), source); 317 DCHECK_EQ(fetcher_.get(), source);
338 std::unique_ptr<net::URLFetcher> free_fetcher = std::move(fetcher_); 318 std::unique_ptr<net::URLFetcher> free_fetcher = std::move(fetcher_);
339 319
340 std::string sketchy_json; 320 std::string json_string;
341 if (!(source->GetStatus().is_success() && 321 if (!(source->GetStatus().is_success() &&
342 source->GetResponseCode() == net::HTTP_OK && 322 source->GetResponseCode() == net::HTTP_OK &&
343 source->GetResponseAsString(&sketchy_json))) { 323 source->GetResponseAsString(&json_string))) {
344 OnDownloadFailed(); 324 OnDownloadFailed();
345 return; 325 return;
346 } 326 }
347 327
348 safe_json::JsonSanitizer::Sanitize( 328 safe_json::SafeJsonParser::Parse(
349 sketchy_json, base::Bind(&PopularSites::OnJsonSanitized, 329 json_string,
350 weak_ptr_factory_.GetWeakPtr()), 330 base::Bind(&PopularSites::OnJsonParsed, weak_ptr_factory_.GetWeakPtr()),
351 base::Bind(&PopularSites::OnJsonSanitizationFailed, 331 base::Bind(&PopularSites::OnJsonParseFailed,
352 weak_ptr_factory_.GetWeakPtr())); 332 weak_ptr_factory_.GetWeakPtr()));
353 } 333 }
354 334
355 void PopularSites::OnJsonSanitized(const std::string& valid_minified_json) { 335 void PopularSites::OnJsonParsed(std::unique_ptr<base::Value> json) {
336 const base::Value* json_ptr = json.get();
356 base::PostTaskAndReplyWithResult( 337 base::PostTaskAndReplyWithResult(
357 blocking_runner_.get(), FROM_HERE, 338 blocking_runner_.get(), FROM_HERE,
358 base::Bind(&base::ImportantFileWriter::WriteFileAtomically, local_path_, 339 base::Bind(&WriteJsonToFile, local_path_, json_ptr),
359 valid_minified_json),
360 base::Bind(&PopularSites::OnFileWriteDone, weak_ptr_factory_.GetWeakPtr(), 340 base::Bind(&PopularSites::OnFileWriteDone, weak_ptr_factory_.GetWeakPtr(),
361 valid_minified_json)); 341 base::Passed(std::move(json))));
362 } 342 }
363 343
364 void PopularSites::OnJsonSanitizationFailed(const std::string& error_message) { 344 void PopularSites::OnJsonParseFailed(const std::string& error_message) {
365 DLOG(WARNING) << "JSON sanitization failed: " << error_message; 345 DLOG(WARNING) << "JSON parsing failed: " << error_message;
366 OnDownloadFailed(); 346 OnDownloadFailed();
367 } 347 }
368 348
369 void PopularSites::OnFileWriteDone(const std::string& json, bool success) { 349 void PopularSites::OnFileWriteDone(std::unique_ptr<base::Value> json,
350 bool success) {
370 if (success) { 351 if (success) {
371 prefs_->SetInt64(kPopularSitesLastDownloadPref, 352 prefs_->SetInt64(kPopularSitesLastDownloadPref,
372 base::Time::Now().ToInternalValue()); 353 base::Time::Now().ToInternalValue());
373 prefs_->SetString(kPopularSitesCountryPref, pending_country_); 354 prefs_->SetString(kPopularSitesCountryPref, pending_country_);
374 prefs_->SetString(kPopularSitesVersionPref, pending_version_); 355 prefs_->SetString(kPopularSitesVersionPref, pending_version_);
375 ParseSiteList(json); 356 ParseSiteList(std::move(json));
376 } else { 357 } else {
377 DLOG(WARNING) << "Could not write file to " 358 DLOG(WARNING) << "Could not write file to "
378 << local_path_.LossyDisplayName(); 359 << local_path_.LossyDisplayName();
379 OnDownloadFailed(); 360 OnDownloadFailed();
380 } 361 }
381 } 362 }
382 363
383 void PopularSites::ParseSiteList(const std::string& json) { 364 void PopularSites::ParseSiteList(std::unique_ptr<base::Value> json) {
384 base::PostTaskAndReplyWithResult( 365 base::ListValue* list = nullptr;
385 blocking_runner_.get(), FROM_HERE, base::Bind(&ParseJson, json), 366 if (!json || !json->GetAsList(&list)) {
386 base::Bind(&PopularSites::OnJsonParsed, weak_ptr_factory_.GetWeakPtr())); 367 DLOG(WARNING) << "JSON is not a list";
387 } 368 sites_.clear();
369 callback_.Run(false);
370 return;
371 }
388 372
389 void PopularSites::OnJsonParsed(std::unique_ptr<std::vector<Site>> sites) { 373 std::vector<PopularSites::Site> sites;
390 if (sites) 374 for (size_t i = 0; i < list->GetSize(); i++) {
391 sites_.swap(*sites); 375 base::DictionaryValue* item;
392 else 376 if (!list->GetDictionary(i, &item))
393 sites_.clear(); 377 continue;
394 callback_.Run(!!sites); 378 base::string16 title;
379 std::string url;
380 if (!item->GetString("title", &title) || !item->GetString("url", &url))
381 continue;
382 std::string favicon_url;
383 item->GetString("favicon_url", &favicon_url);
384 std::string thumbnail_url;
385 item->GetString("thumbnail_url", &thumbnail_url);
386 std::string large_icon_url;
387 item->GetString("large_icon_url", &large_icon_url);
388
389 sites.push_back(PopularSites::Site(title, GURL(url), GURL(favicon_url),
390 GURL(large_icon_url),
391 GURL(thumbnail_url)));
392 }
393
394 sites_.swap(sites);
395 callback_.Run(true);
395 } 396 }
396 397
397 void PopularSites::OnDownloadFailed() { 398 void PopularSites::OnDownloadFailed() {
398 if (!is_fallback_) { 399 if (!is_fallback_) {
399 DLOG(WARNING) << "Download country site list failed"; 400 DLOG(WARNING) << "Download country site list failed";
400 is_fallback_ = true; 401 is_fallback_ = true;
401 pending_country_ = kPopularSitesDefaultCountryCode; 402 pending_country_ = kPopularSitesDefaultCountryCode;
402 pending_version_ = kPopularSitesDefaultVersion; 403 pending_version_ = kPopularSitesDefaultVersion;
403 FetchPopularSites(GetPopularSitesURL()); 404 FetchPopularSites(GetPopularSitesURL());
404 } else { 405 } else {
405 DLOG(WARNING) << "Download fallback site list failed"; 406 DLOG(WARNING) << "Download fallback site list failed";
406 callback_.Run(false); 407 callback_.Run(false);
407 } 408 }
408 } 409 }
OLDNEW
« no previous file with comments | « chrome/browser/android/ntp/popular_sites.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698