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

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
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 // Must run on the blocking thread pool.
130 const std::string& json) { 130 bool WriteJson(const base::FilePath& local_path, const base::Value* json) {
Marc Treib 2016/06/02 11:39:55 nit: WriteJsonToFile?
sfiera 2016/06/02 12:44:19 Done.
131 std::unique_ptr<base::Value> value = 131 std::string json_string;
132 base::JSONReader::Read(json, base::JSON_ALLOW_TRAILING_COMMAS); 132 return base::JSONWriter::Write(*json, &json_string) &&
133 base::ListValue* list; 133 base::ImportantFileWriter::WriteFileAtomically(local_path,
134 if (!value || !value->GetAsList(&list)) { 134 json_string);
135 DLOG(WARNING) << "Failed parsing json";
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 } 135 }
163 136
164 } // namespace 137 } // namespace
165 138
166 base::FilePath ChromePopularSites::GetDirectory() { 139 base::FilePath ChromePopularSites::GetDirectory() {
167 base::FilePath dir; 140 base::FilePath dir;
168 PathService::Get(chrome::DIR_USER_DATA, &dir); 141 PathService::Get(chrome::DIR_USER_DATA, &dir);
169 return dir; // empty if PathService::Get() failed. 142 return dir; // empty if PathService::Get() failed.
170 } 143 }
171 144
(...skipping 138 matching lines...) Expand 10 before | Expand all | Expand 10 after
310 GURL PopularSites::GetPopularSitesURL() const { 283 GURL PopularSites::GetPopularSitesURL() const {
311 return GURL(base::StringPrintf(kPopularSitesURLFormat, 284 return GURL(base::StringPrintf(kPopularSitesURLFormat,
312 pending_country_.c_str(), 285 pending_country_.c_str(),
313 pending_version_.c_str())); 286 pending_version_.c_str()));
314 } 287 }
315 288
316 void PopularSites::OnReadFileDone(const GURL& url, 289 void PopularSites::OnReadFileDone(const GURL& url,
317 std::unique_ptr<std::string> data, 290 std::unique_ptr<std::string> data,
318 bool success) { 291 bool success) {
319 if (success) { 292 if (success) {
320 ParseSiteList(*data); 293 safe_json::SafeJsonParser::Parse(
Marc Treib 2016/06/02 11:39:54 I might be missing something, but why do we need t
sfiera 2016/06/02 12:44:19 We don't have to, but it was easier. I changed it.
Marc Treib 2016/06/02 13:00:39 Well, the threat of malicious json, which might tr
294 *data,
295 base::Bind(&PopularSites::OnJsonParsed, weak_ptr_factory_.GetWeakPtr(),
296 false /* write_to_file */),
297 base::Bind(&PopularSites::OnJsonParseFailed,
298 weak_ptr_factory_.GetWeakPtr()));
321 } else { 299 } else {
322 // File didn't exist, or couldn't be read for some other reason. 300 // File didn't exist, or couldn't be read for some other reason.
323 FetchPopularSites(url); 301 FetchPopularSites(url);
324 } 302 }
325 } 303 }
326 304
327 void PopularSites::FetchPopularSites(const GURL& url) { 305 void PopularSites::FetchPopularSites(const GURL& url) {
328 fetcher_ = URLFetcher::Create(url, URLFetcher::GET, this); 306 fetcher_ = URLFetcher::Create(url, URLFetcher::GET, this);
329 fetcher_->SetRequestContext(download_context_); 307 fetcher_->SetRequestContext(download_context_);
330 fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | 308 fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES |
331 net::LOAD_DO_NOT_SAVE_COOKIES); 309 net::LOAD_DO_NOT_SAVE_COOKIES);
332 fetcher_->SetAutomaticallyRetryOnNetworkChanges(1); 310 fetcher_->SetAutomaticallyRetryOnNetworkChanges(1);
333 fetcher_->Start(); 311 fetcher_->Start();
334 } 312 }
335 313
336 void PopularSites::OnURLFetchComplete(const net::URLFetcher* source) { 314 void PopularSites::OnURLFetchComplete(const net::URLFetcher* source) {
337 DCHECK_EQ(fetcher_.get(), source); 315 DCHECK_EQ(fetcher_.get(), source);
338 std::unique_ptr<net::URLFetcher> free_fetcher = std::move(fetcher_); 316 std::unique_ptr<net::URLFetcher> free_fetcher = std::move(fetcher_);
339 317
340 std::string sketchy_json; 318 std::string json_string;
341 if (!(source->GetStatus().is_success() && 319 if (!(source->GetStatus().is_success() &&
342 source->GetResponseCode() == net::HTTP_OK && 320 source->GetResponseCode() == net::HTTP_OK &&
343 source->GetResponseAsString(&sketchy_json))) { 321 source->GetResponseAsString(&json_string))) {
344 OnDownloadFailed(); 322 OnDownloadFailed();
345 return; 323 return;
346 } 324 }
347 325
348 safe_json::JsonSanitizer::Sanitize( 326 safe_json::SafeJsonParser::Parse(
349 sketchy_json, base::Bind(&PopularSites::OnJsonSanitized, 327 json_string,
350 weak_ptr_factory_.GetWeakPtr()), 328 base::Bind(&PopularSites::OnJsonParsed, weak_ptr_factory_.GetWeakPtr(),
351 base::Bind(&PopularSites::OnJsonSanitizationFailed, 329 true /* write_to_file */),
330 base::Bind(&PopularSites::OnJsonParseFailed,
352 weak_ptr_factory_.GetWeakPtr())); 331 weak_ptr_factory_.GetWeakPtr()));
353 } 332 }
354 333
355 void PopularSites::OnJsonSanitized(const std::string& valid_minified_json) { 334 void PopularSites::OnJsonParsed(bool write_to_file,
356 base::PostTaskAndReplyWithResult( 335 std::unique_ptr<base::Value> json) {
357 blocking_runner_.get(), FROM_HERE, 336 if (write_to_file) {
358 base::Bind(&base::ImportantFileWriter::WriteFileAtomically, local_path_, 337 const base::Value* json_ptr = json.get();
359 valid_minified_json), 338 base::PostTaskAndReplyWithResult(
360 base::Bind(&PopularSites::OnFileWriteDone, weak_ptr_factory_.GetWeakPtr(), 339 blocking_runner_.get(), FROM_HERE,
361 valid_minified_json)); 340 base::Bind(&WriteJson, local_path_, json_ptr),
341 base::Bind(&PopularSites::OnFileWriteDone,
342 weak_ptr_factory_.GetWeakPtr(),
343 base::Passed(std::move(json))));
344 } else {
345 ParseSiteList(std::move(json));
346 }
362 } 347 }
363 348
364 void PopularSites::OnJsonSanitizationFailed(const std::string& error_message) { 349 void PopularSites::OnJsonParseFailed(const std::string& error_message) {
365 DLOG(WARNING) << "JSON sanitization failed: " << error_message; 350 DLOG(WARNING) << "JSON parsing failed: " << error_message;
366 OnDownloadFailed(); 351 OnDownloadFailed();
367 } 352 }
368 353
369 void PopularSites::OnFileWriteDone(const std::string& json, bool success) { 354 void PopularSites::OnFileWriteDone(std::unique_ptr<base::Value> json,
355 bool success) {
370 if (success) { 356 if (success) {
371 prefs_->SetInt64(kPopularSitesLastDownloadPref, 357 prefs_->SetInt64(kPopularSitesLastDownloadPref,
372 base::Time::Now().ToInternalValue()); 358 base::Time::Now().ToInternalValue());
373 prefs_->SetString(kPopularSitesCountryPref, pending_country_); 359 prefs_->SetString(kPopularSitesCountryPref, pending_country_);
374 prefs_->SetString(kPopularSitesVersionPref, pending_version_); 360 prefs_->SetString(kPopularSitesVersionPref, pending_version_);
375 ParseSiteList(json); 361 ParseSiteList(std::move(json));
376 } else { 362 } else {
377 DLOG(WARNING) << "Could not write file to " 363 DLOG(WARNING) << "Could not write file to "
378 << local_path_.LossyDisplayName(); 364 << local_path_.LossyDisplayName();
379 OnDownloadFailed(); 365 OnDownloadFailed();
380 } 366 }
381 } 367 }
382 368
383 void PopularSites::ParseSiteList(const std::string& json) { 369 void PopularSites::ParseSiteList(std::unique_ptr<base::Value> json) {
384 base::PostTaskAndReplyWithResult( 370 base::ListValue* list;
Marc Treib 2016/06/02 11:39:55 nit: initialize to nullptr?
sfiera 2016/06/02 12:44:19 Sure, it's your code :) I just moved it.
Marc Treib 2016/06/02 13:00:39 Haha, alright. I guess my reviewer was lazy (or le
385 blocking_runner_.get(), FROM_HERE, base::Bind(&ParseJson, json), 371 if (!json || !json->GetAsList(&list)) {
386 base::Bind(&PopularSites::OnJsonParsed, weak_ptr_factory_.GetWeakPtr())); 372 DLOG(WARNING) << "JSON is not a list";
387 } 373 sites_.clear();
374 callback_.Run(false);
375 return;
376 }
388 377
389 void PopularSites::OnJsonParsed(std::unique_ptr<std::vector<Site>> sites) { 378 std::vector<PopularSites::Site> sites;
390 if (sites) 379 for (size_t i = 0; i < list->GetSize(); i++) {
391 sites_.swap(*sites); 380 base::DictionaryValue* item;
392 else 381 if (!list->GetDictionary(i, &item))
393 sites_.clear(); 382 continue;
394 callback_.Run(!!sites); 383 base::string16 title;
384 std::string url;
385 if (!item->GetString("title", &title) || !item->GetString("url", &url))
386 continue;
387 std::string favicon_url;
388 item->GetString("favicon_url", &favicon_url);
389 std::string thumbnail_url;
390 item->GetString("thumbnail_url", &thumbnail_url);
391 std::string large_icon_url;
392 item->GetString("large_icon_url", &large_icon_url);
393
394 sites.push_back(PopularSites::Site(title, GURL(url), GURL(favicon_url),
395 GURL(large_icon_url),
396 GURL(thumbnail_url)));
397 }
398
399 sites_.swap(sites);
400 callback_.Run(true);
395 } 401 }
396 402
397 void PopularSites::OnDownloadFailed() { 403 void PopularSites::OnDownloadFailed() {
398 if (!is_fallback_) { 404 if (!is_fallback_) {
399 DLOG(WARNING) << "Download country site list failed"; 405 DLOG(WARNING) << "Download country site list failed";
400 is_fallback_ = true; 406 is_fallback_ = true;
401 pending_country_ = kPopularSitesDefaultCountryCode; 407 pending_country_ = kPopularSitesDefaultCountryCode;
402 pending_version_ = kPopularSitesDefaultVersion; 408 pending_version_ = kPopularSitesDefaultVersion;
403 FetchPopularSites(GetPopularSitesURL()); 409 FetchPopularSites(GetPopularSitesURL());
404 } else { 410 } else {
405 DLOG(WARNING) << "Download fallback site list failed"; 411 DLOG(WARNING) << "Download fallback site list failed";
406 callback_.Run(false); 412 callback_.Run(false);
407 } 413 }
408 } 414 }
OLDNEW
« chrome/browser/android/ntp/popular_sites.h ('K') | « 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