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

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_writer.h"
15 #include "base/path_service.h" 15 #include "base/path_service.h"
16 #include "base/strings/string_util.h" 16 #include "base/strings/string_util.h"
17 #include "base/strings/stringprintf.h" 17 #include "base/strings/stringprintf.h"
18 #include "base/task_runner_util.h" 18 #include "base/task_runner_util.h"
19 #include "base/time/time.h" 19 #include "base/time/time.h"
20 #include "base/values.h" 20 #include "base/values.h"
21 #include "chrome/common/chrome_paths.h" 21 #include "chrome/common/chrome_paths.h"
22 #include "components/google/core/browser/google_util.h" 22 #include "components/google/core/browser/google_util.h"
23 #include "components/ntp_tiles/pref_names.h" 23 #include "components/ntp_tiles/pref_names.h"
24 #include "components/ntp_tiles/switches.h" 24 #include "components/ntp_tiles/switches.h"
25 #include "components/pref_registry/pref_registry_syncable.h" 25 #include "components/pref_registry/pref_registry_syncable.h"
26 #include "components/prefs/pref_service.h" 26 #include "components/prefs/pref_service.h"
27 #include "components/safe_json/json_sanitizer.h" 27 #include "components/safe_json/safe_json_parser.h"
28 #include "components/search_engines/search_engine_type.h" 28 #include "components/search_engines/search_engine_type.h"
29 #include "components/search_engines/template_url_prepopulate_data.h" 29 #include "components/search_engines/template_url_prepopulate_data.h"
30 #include "components/search_engines/template_url_service.h" 30 #include "components/search_engines/template_url_service.h"
31 #include "components/variations/service/variations_service.h" 31 #include "components/variations/service/variations_service.h"
32 #include "net/base/load_flags.h" 32 #include "net/base/load_flags.h"
33 #include "net/http/http_status_code.h" 33 #include "net/http/http_status_code.h"
34 34
35 using net::URLFetcher; 35 using net::URLFetcher;
36 using variations::VariationsService; 36 using variations::VariationsService;
37 37
(...skipping 81 matching lines...) Expand 10 before | Expand all | Expand 10 after
119 119
120 if (version.empty()) 120 if (version.empty())
121 version = variation_param_version; 121 version = variation_param_version;
122 122
123 if (version.empty()) 123 if (version.empty())
124 version = kPopularSitesDefaultVersion; 124 version = kPopularSitesDefaultVersion;
125 125
126 return version; 126 return version;
127 } 127 }
128 128
129 std::unique_ptr<std::vector<PopularSites::Site>> ParseJson( 129 std::unique_ptr<std::vector<PopularSites::Site>> UnmarshalJson(
Marc Treib 2016/06/02 08:32:11 IMO "unmarshal" isn't the right term here - we're
sfiera 2016/06/02 11:07:59 Yep, inlined.
130 const std::string& json) { 130 std::unique_ptr<base::Value> value) {
131 std::unique_ptr<base::Value> value =
132 base::JSONReader::Read(json, base::JSON_ALLOW_TRAILING_COMMAS);
133 base::ListValue* list; 131 base::ListValue* list;
134 if (!value || !value->GetAsList(&list)) { 132 if (!value || !value->GetAsList(&list)) {
135 DLOG(WARNING) << "Failed parsing json"; 133 DLOG(WARNING) << "Failed parsing json";
136 return nullptr; 134 return nullptr;
137 } 135 }
138 136
139 std::unique_ptr<std::vector<PopularSites::Site>> sites( 137 std::unique_ptr<std::vector<PopularSites::Site>> sites(
140 new std::vector<PopularSites::Site>); 138 new std::vector<PopularSites::Site>);
141 for (size_t i = 0; i < list->GetSize(); i++) { 139 for (size_t i = 0; i < list->GetSize(); i++) {
142 base::DictionaryValue* item; 140 base::DictionaryValue* item;
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 GURL PopularSites::GetPopularSitesURL() const { 308 GURL PopularSites::GetPopularSitesURL() const {
311 return GURL(base::StringPrintf(kPopularSitesURLFormat, 309 return GURL(base::StringPrintf(kPopularSitesURLFormat,
312 pending_country_.c_str(), 310 pending_country_.c_str(),
313 pending_version_.c_str())); 311 pending_version_.c_str()));
314 } 312 }
315 313
316 void PopularSites::OnReadFileDone(const GURL& url, 314 void PopularSites::OnReadFileDone(const GURL& url,
317 std::unique_ptr<std::string> data, 315 std::unique_ptr<std::string> data,
318 bool success) { 316 bool success) {
319 if (success) { 317 if (success) {
320 ParseSiteList(*data); 318 safe_json::SafeJsonParser::Parse(
319 *data,
320 base::Bind(&PopularSites::OnJsonParsed, weak_ptr_factory_.GetWeakPtr(),
321 false /* write_to_file */),
322 base::Bind(&PopularSites::OnJsonParseFailed,
323 weak_ptr_factory_.GetWeakPtr()));
321 } else { 324 } else {
322 // File didn't exist, or couldn't be read for some other reason. 325 // File didn't exist, or couldn't be read for some other reason.
323 FetchPopularSites(url); 326 FetchPopularSites(url);
324 } 327 }
325 } 328 }
326 329
327 void PopularSites::FetchPopularSites(const GURL& url) { 330 void PopularSites::FetchPopularSites(const GURL& url) {
328 fetcher_ = URLFetcher::Create(url, URLFetcher::GET, this); 331 fetcher_ = URLFetcher::Create(url, URLFetcher::GET, this);
329 fetcher_->SetRequestContext(download_context_); 332 fetcher_->SetRequestContext(download_context_);
330 fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | 333 fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
331 net::LOAD_DO_NOT_SAVE_COOKIES); 334 net::LOAD_DO_NOT_SAVE_COOKIES);
332 fetcher_->SetAutomaticallyRetryOnNetworkChanges(1); 335 fetcher_->SetAutomaticallyRetryOnNetworkChanges(1);
333 fetcher_->Start(); 336 fetcher_->Start();
334 } 337 }
335 338
336 void PopularSites::OnURLFetchComplete(const net::URLFetcher* source) { 339 void PopularSites::OnURLFetchComplete(const net::URLFetcher* source) {
337 DCHECK_EQ(fetcher_.get(), source); 340 DCHECK_EQ(fetcher_.get(), source);
338 std::unique_ptr<net::URLFetcher> free_fetcher = std::move(fetcher_); 341 std::unique_ptr<net::URLFetcher> free_fetcher = std::move(fetcher_);
339 342
340 std::string sketchy_json; 343 std::string json_string;
341 if (!(source->GetStatus().is_success() && 344 if (!(source->GetStatus().is_success() &&
342 source->GetResponseCode() == net::HTTP_OK && 345 source->GetResponseCode() == net::HTTP_OK &&
343 source->GetResponseAsString(&sketchy_json))) { 346 source->GetResponseAsString(&json_string))) {
344 OnDownloadFailed(); 347 OnDownloadFailed();
345 return; 348 return;
346 } 349 }
347 350
348 safe_json::JsonSanitizer::Sanitize( 351 safe_json::SafeJsonParser::Parse(
349 sketchy_json, base::Bind(&PopularSites::OnJsonSanitized, 352 json_string,
350 weak_ptr_factory_.GetWeakPtr()), 353 base::Bind(&PopularSites::OnJsonParsed, weak_ptr_factory_.GetWeakPtr(),
351 base::Bind(&PopularSites::OnJsonSanitizationFailed, 354 true /* write_to_file */),
355 base::Bind(&PopularSites::OnJsonParseFailed,
352 weak_ptr_factory_.GetWeakPtr())); 356 weak_ptr_factory_.GetWeakPtr()));
353 } 357 }
354 358
355 void PopularSites::OnJsonSanitized(const std::string& valid_minified_json) { 359 void PopularSites::OnJsonParsed(bool write_to_file,
356 base::PostTaskAndReplyWithResult( 360 std::unique_ptr<base::Value> json) {
357 blocking_runner_.get(), FROM_HERE, 361 std::string json_string;
Marc Treib 2016/06/02 08:32:11 Shouldn't this be inside the "if (write_to_file)"?
sfiera 2016/06/02 11:07:59 Done. (actually, moved into the blocking thread po
358 base::Bind(&base::ImportantFileWriter::WriteFileAtomically, local_path_, 362 if (!base::JSONWriter::Write(*json, &json_string)) {
359 valid_minified_json), 363 // DO_NOT_SUBMIT: fail
Marc Treib 2016/06/02 08:32:11 :)
sfiera 2016/06/02 11:07:59 It was indeed a DO_NOT_SUBMIT-fail.
360 base::Bind(&PopularSites::OnFileWriteDone, weak_ptr_factory_.GetWeakPtr(), 364 }
361 valid_minified_json)); 365 if (write_to_file) {
366 base::PostTaskAndReplyWithResult(
367 blocking_runner_.get(), FROM_HERE,
368 base::Bind(&base::ImportantFileWriter::WriteFileAtomically, local_path_,
369 json_string),
370 base::Bind(&PopularSites::OnFileWriteDone,
371 weak_ptr_factory_.GetWeakPtr(),
372 base::Passed(std::move(json))));
373 } else {
374 ParseSiteList(std::move(json));
375 }
362 } 376 }
363 377
364 void PopularSites::OnJsonSanitizationFailed(const std::string& error_message) { 378 void PopularSites::OnJsonParseFailed(const std::string& error_message) {
365 DLOG(WARNING) << "JSON sanitization failed: " << error_message; 379 DLOG(WARNING) << "JSON parsing failed: " << error_message;
366 OnDownloadFailed(); 380 OnDownloadFailed();
367 } 381 }
368 382
369 void PopularSites::OnFileWriteDone(const std::string& json, bool success) { 383 void PopularSites::OnFileWriteDone(std::unique_ptr<base::Value> json,
384 bool success) {
370 if (success) { 385 if (success) {
371 prefs_->SetInt64(kPopularSitesLastDownloadPref, 386 prefs_->SetInt64(kPopularSitesLastDownloadPref,
372 base::Time::Now().ToInternalValue()); 387 base::Time::Now().ToInternalValue());
373 prefs_->SetString(kPopularSitesCountryPref, pending_country_); 388 prefs_->SetString(kPopularSitesCountryPref, pending_country_);
374 prefs_->SetString(kPopularSitesVersionPref, pending_version_); 389 prefs_->SetString(kPopularSitesVersionPref, pending_version_);
375 ParseSiteList(json); 390 ParseSiteList(std::move(json));
376 } else { 391 } else {
377 DLOG(WARNING) << "Could not write file to " 392 DLOG(WARNING) << "Could not write file to "
378 << local_path_.LossyDisplayName(); 393 << local_path_.LossyDisplayName();
379 OnDownloadFailed(); 394 OnDownloadFailed();
380 } 395 }
381 } 396 }
382 397
383 void PopularSites::ParseSiteList(const std::string& json) { 398 void PopularSites::ParseSiteList(std::unique_ptr<base::Value> json) {
384 base::PostTaskAndReplyWithResult( 399 base::PostTaskAndReplyWithResult(
385 blocking_runner_.get(), FROM_HERE, base::Bind(&ParseJson, json), 400 blocking_runner_.get(), FROM_HERE,
386 base::Bind(&PopularSites::OnJsonParsed, weak_ptr_factory_.GetWeakPtr())); 401 base::Bind(&UnmarshalJson, base::Passed(std::move(json))),
Marc Treib 2016/06/02 08:32:11 Any reason why this happens asynchronously? I thin
sfiera 2016/06/02 11:07:59 It was to keep ParseJson off the UI thread, but we
402 base::Bind(&PopularSites::OnJsonUnmarshaled,
403 weak_ptr_factory_.GetWeakPtr()));
387 } 404 }
388 405
389 void PopularSites::OnJsonParsed(std::unique_ptr<std::vector<Site>> sites) { 406 void PopularSites::OnJsonUnmarshaled(std::unique_ptr<std::vector<Site>> sites) {
390 if (sites) 407 if (sites)
391 sites_.swap(*sites); 408 sites_.swap(*sites);
392 else 409 else
393 sites_.clear(); 410 sites_.clear();
394 callback_.Run(!!sites); 411 callback_.Run(!!sites);
sfiera 2016/06/02 08:49:28 Whoa, wait, shouldn't this be !!sites_ (note the u
sfiera 2016/06/02 11:07:59 Fixed to be less confusing.
395 } 412 }
396 413
397 void PopularSites::OnDownloadFailed() { 414 void PopularSites::OnDownloadFailed() {
398 if (!is_fallback_) { 415 if (!is_fallback_) {
399 DLOG(WARNING) << "Download country site list failed"; 416 DLOG(WARNING) << "Download country site list failed";
400 is_fallback_ = true; 417 is_fallback_ = true;
401 pending_country_ = kPopularSitesDefaultCountryCode; 418 pending_country_ = kPopularSitesDefaultCountryCode;
402 pending_version_ = kPopularSitesDefaultVersion; 419 pending_version_ = kPopularSitesDefaultVersion;
403 FetchPopularSites(GetPopularSitesURL()); 420 FetchPopularSites(GetPopularSitesURL());
404 } else { 421 } else {
405 DLOG(WARNING) << "Download fallback site list failed"; 422 DLOG(WARNING) << "Download fallback site list failed";
406 callback_.Run(false); 423 callback_.Run(false);
407 } 424 }
408 } 425 }
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