OLD | NEW |
1 // Copyright 2016 The Chromium Authors. All rights reserved. | 1 // Copyright 2016 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 "components/ntp_snippets/remote/ntp_snippets_fetcher.h" | 5 #include "components/ntp_snippets/remote/ntp_snippets_fetcher.h" |
6 | 6 |
7 #include <cstdlib> | 7 #include <cstdlib> |
8 | 8 |
9 #include "base/command_line.h" | 9 #include "base/command_line.h" |
10 #include "base/files/file_path.h" | 10 #include "base/files/file_path.h" |
(...skipping 119 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
130 return true; | 130 return true; |
131 } | 131 } |
132 | 132 |
133 // Creates snippets from dictionary values in |list| and adds them to | 133 // Creates snippets from dictionary values in |list| and adds them to |
134 // |snippets|. Returns true on success, false if anything went wrong. | 134 // |snippets|. Returns true on success, false if anything went wrong. |
135 bool AddSnippetsFromListValue(bool content_suggestions_api, | 135 bool AddSnippetsFromListValue(bool content_suggestions_api, |
136 const base::ListValue& list, | 136 const base::ListValue& list, |
137 NTPSnippet::PtrVector* snippets) { | 137 NTPSnippet::PtrVector* snippets) { |
138 for (const auto& value : list) { | 138 for (const auto& value : list) { |
139 const base::DictionaryValue* dict = nullptr; | 139 const base::DictionaryValue* dict = nullptr; |
140 if (!value->GetAsDictionary(&dict)) | 140 if (!value->GetAsDictionary(&dict)) { |
141 return false; | 141 return false; |
| 142 } |
142 | 143 |
143 std::unique_ptr<NTPSnippet> snippet; | 144 std::unique_ptr<NTPSnippet> snippet; |
144 if (content_suggestions_api) { | 145 if (content_suggestions_api) { |
145 snippet = NTPSnippet::CreateFromContentSuggestionsDictionary(*dict); | 146 snippet = NTPSnippet::CreateFromContentSuggestionsDictionary(*dict); |
146 } else { | 147 } else { |
147 snippet = NTPSnippet::CreateFromChromeReaderDictionary(*dict); | 148 snippet = NTPSnippet::CreateFromChromeReaderDictionary(*dict); |
148 } | 149 } |
149 if (!snippet) | 150 if (!snippet) { |
150 return false; | 151 return false; |
| 152 } |
151 | 153 |
152 snippets->push_back(std::move(snippet)); | 154 snippets->push_back(std::move(snippet)); |
153 } | 155 } |
154 return true; | 156 return true; |
155 } | 157 } |
156 | 158 |
157 // Translate the BCP 47 |language_code| into a posix locale string. | 159 // Translate the BCP 47 |language_code| into a posix locale string. |
158 std::string PosixLocaleFromBCP47Language(const std::string& language_code) { | 160 std::string PosixLocaleFromBCP47Language(const std::string& language_code) { |
159 char locale[ULOC_FULLNAME_CAPACITY]; | 161 char locale[ULOC_FULLNAME_CAPACITY]; |
160 UErrorCode error = U_ZERO_ERROR; | 162 UErrorCode error = U_ZERO_ERROR; |
(...skipping 70 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
231 snippets_available_callback_ = callback; | 233 snippets_available_callback_ = callback; |
232 } | 234 } |
233 | 235 |
234 void NTPSnippetsFetcher::FetchSnippetsFromHosts( | 236 void NTPSnippetsFetcher::FetchSnippetsFromHosts( |
235 const std::set<std::string>& hosts, | 237 const std::set<std::string>& hosts, |
236 const std::string& language_code, | 238 const std::string& language_code, |
237 const std::set<std::string>& excluded_ids, | 239 const std::set<std::string>& excluded_ids, |
238 int count, | 240 int count, |
239 bool interactive_request) { | 241 bool interactive_request) { |
240 if (!request_throttler_.DemandQuotaForRequest(interactive_request)) { | 242 if (!request_throttler_.DemandQuotaForRequest(interactive_request)) { |
241 FetchFinished(OptionalSnippets(), | 243 FetchFinished(OptionalFetchedCategories(), |
242 interactive_request | 244 interactive_request |
243 ? FetchResult::INTERACTIVE_QUOTA_ERROR | 245 ? FetchResult::INTERACTIVE_QUOTA_ERROR |
244 : FetchResult::NON_INTERACTIVE_QUOTA_ERROR, | 246 : FetchResult::NON_INTERACTIVE_QUOTA_ERROR, |
245 /*extra_message=*/std::string()); | 247 /*extra_message=*/std::string()); |
246 return; | 248 return; |
247 } | 249 } |
248 | 250 |
249 hosts_ = hosts; | 251 hosts_ = hosts; |
250 fetch_start_time_ = tick_clock_->NowTicks(); | 252 fetch_start_time_ = tick_clock_->NowTicks(); |
251 excluded_ids_ = excluded_ids; | 253 excluded_ids_ = excluded_ids; |
(...skipping 225 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
477 error.state() == GoogleServiceAuthError::State::REQUEST_CANCELED) { | 479 error.state() == GoogleServiceAuthError::State::REQUEST_CANCELED) { |
478 // The request (especially on startup) can get reset by loading the refresh | 480 // The request (especially on startup) can get reset by loading the refresh |
479 // token - do it one more time. | 481 // token - do it one more time. |
480 oauth_token_retried_ = true; | 482 oauth_token_retried_ = true; |
481 StartTokenRequest(); | 483 StartTokenRequest(); |
482 return; | 484 return; |
483 } | 485 } |
484 | 486 |
485 DLOG(ERROR) << "Unable to get token: " << error.ToString(); | 487 DLOG(ERROR) << "Unable to get token: " << error.ToString(); |
486 FetchFinished( | 488 FetchFinished( |
487 OptionalSnippets(), FetchResult::OAUTH_TOKEN_ERROR, | 489 OptionalFetchedCategories(), FetchResult::OAUTH_TOKEN_ERROR, |
488 /*extra_message=*/base::StringPrintf(" (%s)", error.ToString().c_str())); | 490 /*extra_message=*/base::StringPrintf(" (%s)", error.ToString().c_str())); |
489 } | 491 } |
490 | 492 |
491 //////////////////////////////////////////////////////////////////////////////// | 493 //////////////////////////////////////////////////////////////////////////////// |
492 // OAuth2TokenService::Observer overrides | 494 // OAuth2TokenService::Observer overrides |
493 void NTPSnippetsFetcher::OnRefreshTokenAvailable( | 495 void NTPSnippetsFetcher::OnRefreshTokenAvailable( |
494 const std::string& account_id) { | 496 const std::string& account_id) { |
495 // Only react on tokens for the account the user has signed in with. | 497 // Only react on tokens for the account the user has signed in with. |
496 if (account_id != signin_manager_->GetAuthenticatedAccountId()) | 498 if (account_id != signin_manager_->GetAuthenticatedAccountId()) |
497 return; | 499 return; |
498 | 500 |
499 token_service_->RemoveObserver(this); | 501 token_service_->RemoveObserver(this); |
500 waiting_for_refresh_token_ = false; | 502 waiting_for_refresh_token_ = false; |
501 oauth_token_retried_ = false; | 503 oauth_token_retried_ = false; |
502 StartTokenRequest(); | 504 StartTokenRequest(); |
503 } | 505 } |
504 | 506 |
505 //////////////////////////////////////////////////////////////////////////////// | 507 //////////////////////////////////////////////////////////////////////////////// |
506 // URLFetcherDelegate overrides | 508 // URLFetcherDelegate overrides |
507 void NTPSnippetsFetcher::OnURLFetchComplete(const URLFetcher* source) { | 509 void NTPSnippetsFetcher::OnURLFetchComplete(const URLFetcher* source) { |
508 DCHECK_EQ(url_fetcher_.get(), source); | 510 DCHECK_EQ(url_fetcher_.get(), source); |
509 | 511 |
510 const URLRequestStatus& status = source->GetStatus(); | 512 const URLRequestStatus& status = source->GetStatus(); |
511 | 513 |
512 UMA_HISTOGRAM_SPARSE_SLOWLY( | 514 UMA_HISTOGRAM_SPARSE_SLOWLY( |
513 "NewTabPage.Snippets.FetchHttpResponseOrErrorCode", | 515 "NewTabPage.Snippets.FetchHttpResponseOrErrorCode", |
514 status.is_success() ? source->GetResponseCode() : status.error()); | 516 status.is_success() ? source->GetResponseCode() : status.error()); |
515 | 517 |
516 if (!status.is_success()) { | 518 if (!status.is_success()) { |
517 FetchFinished(OptionalSnippets(), FetchResult::URL_REQUEST_STATUS_ERROR, | 519 FetchFinished(OptionalFetchedCategories(), |
| 520 FetchResult::URL_REQUEST_STATUS_ERROR, |
518 /*extra_message=*/base::StringPrintf(" %d", status.error())); | 521 /*extra_message=*/base::StringPrintf(" %d", status.error())); |
519 } else if (source->GetResponseCode() != net::HTTP_OK) { | 522 } else if (source->GetResponseCode() != net::HTTP_OK) { |
520 // TODO(jkrcal): https://crbug.com/609084 | 523 // TODO(jkrcal): https://crbug.com/609084 |
521 // We need to deal with the edge case again where the auth | 524 // We need to deal with the edge case again where the auth |
522 // token expires just before we send the request (in which case we need to | 525 // token expires just before we send the request (in which case we need to |
523 // fetch a new auth token). We should extract that into a common class | 526 // fetch a new auth token). We should extract that into a common class |
524 // instead of adding it to every single class that uses auth tokens. | 527 // instead of adding it to every single class that uses auth tokens. |
525 FetchFinished( | 528 FetchFinished( |
526 OptionalSnippets(), FetchResult::HTTP_ERROR, | 529 OptionalFetchedCategories(), FetchResult::HTTP_ERROR, |
527 /*extra_message=*/base::StringPrintf(" %d", source->GetResponseCode())); | 530 /*extra_message=*/base::StringPrintf(" %d", source->GetResponseCode())); |
528 } else { | 531 } else { |
529 bool stores_result_to_string = | 532 bool stores_result_to_string = |
530 source->GetResponseAsString(&last_fetch_json_); | 533 source->GetResponseAsString(&last_fetch_json_); |
531 DCHECK(stores_result_to_string); | 534 DCHECK(stores_result_to_string); |
532 | 535 |
533 parse_json_callback_.Run(last_fetch_json_, | 536 parse_json_callback_.Run(last_fetch_json_, |
534 base::Bind(&NTPSnippetsFetcher::OnJsonParsed, | 537 base::Bind(&NTPSnippetsFetcher::OnJsonParsed, |
535 weak_ptr_factory_.GetWeakPtr()), | 538 weak_ptr_factory_.GetWeakPtr()), |
536 base::Bind(&NTPSnippetsFetcher::OnJsonError, | 539 base::Bind(&NTPSnippetsFetcher::OnJsonError, |
(...skipping 54 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
591 return true; | 594 return true; |
592 } | 595 } |
593 } | 596 } |
594 NOTREACHED(); | 597 NOTREACHED(); |
595 return false; | 598 return false; |
596 } | 599 } |
597 | 600 |
598 void NTPSnippetsFetcher::OnJsonParsed(std::unique_ptr<base::Value> parsed) { | 601 void NTPSnippetsFetcher::OnJsonParsed(std::unique_ptr<base::Value> parsed) { |
599 FetchedCategoriesVector categories; | 602 FetchedCategoriesVector categories; |
600 if (JsonToSnippets(*parsed, &categories)) { | 603 if (JsonToSnippets(*parsed, &categories)) { |
601 FetchFinished(OptionalSnippets(std::move(categories)), FetchResult::SUCCESS, | 604 FetchFinished(OptionalFetchedCategories(std::move(categories)), |
| 605 FetchResult::SUCCESS, |
602 /*extra_message=*/std::string()); | 606 /*extra_message=*/std::string()); |
603 } else { | 607 } else { |
604 LOG(WARNING) << "Received invalid snippets: " << last_fetch_json_; | 608 LOG(WARNING) << "Received invalid snippets: " << last_fetch_json_; |
605 FetchFinished(OptionalSnippets(), | 609 FetchFinished(OptionalFetchedCategories(), |
606 FetchResult::INVALID_SNIPPET_CONTENT_ERROR, | 610 FetchResult::INVALID_SNIPPET_CONTENT_ERROR, |
607 /*extra_message=*/std::string()); | 611 /*extra_message=*/std::string()); |
608 } | 612 } |
609 } | 613 } |
610 | 614 |
611 void NTPSnippetsFetcher::OnJsonError(const std::string& error) { | 615 void NTPSnippetsFetcher::OnJsonError(const std::string& error) { |
612 LOG(WARNING) << "Received invalid JSON (" << error | 616 LOG(WARNING) << "Received invalid JSON (" << error |
613 << "): " << last_fetch_json_; | 617 << "): " << last_fetch_json_; |
614 FetchFinished( | 618 FetchFinished( |
615 OptionalSnippets(), FetchResult::JSON_PARSE_ERROR, | 619 OptionalFetchedCategories(), FetchResult::JSON_PARSE_ERROR, |
616 /*extra_message=*/base::StringPrintf(" (error %s)", error.c_str())); | 620 /*extra_message=*/base::StringPrintf(" (error %s)", error.c_str())); |
617 } | 621 } |
618 | 622 |
619 void NTPSnippetsFetcher::FetchFinished(OptionalSnippets snippets, | 623 void NTPSnippetsFetcher::FetchFinished( |
620 FetchResult result, | 624 OptionalFetchedCategories fetched_categories, |
621 const std::string& extra_message) { | 625 FetchResult result, |
622 DCHECK(result == FetchResult::SUCCESS || !snippets); | 626 const std::string& extra_message) { |
| 627 DCHECK(result == FetchResult::SUCCESS || !fetched_categories); |
623 last_status_ = FetchResultToString(result) + extra_message; | 628 last_status_ = FetchResultToString(result) + extra_message; |
624 | 629 |
625 // Don't record FetchTimes if the result indicates that a precondition | 630 // Don't record FetchTimes if the result indicates that a precondition |
626 // failed and we never actually sent a network request | 631 // failed and we never actually sent a network request |
627 if (!IsFetchPreconditionFailed(result)) { | 632 if (!IsFetchPreconditionFailed(result)) { |
628 UMA_HISTOGRAM_TIMES("NewTabPage.Snippets.FetchTime", | 633 UMA_HISTOGRAM_TIMES("NewTabPage.Snippets.FetchTime", |
629 tick_clock_->NowTicks() - fetch_start_time_); | 634 tick_clock_->NowTicks() - fetch_start_time_); |
630 } | 635 } |
631 UMA_HISTOGRAM_ENUMERATION("NewTabPage.Snippets.FetchResult", | 636 UMA_HISTOGRAM_ENUMERATION("NewTabPage.Snippets.FetchResult", |
632 static_cast<int>(result), | 637 static_cast<int>(result), |
633 static_cast<int>(FetchResult::RESULT_MAX)); | 638 static_cast<int>(FetchResult::RESULT_MAX)); |
634 | 639 |
635 DVLOG(1) << "Fetch finished: " << last_status_; | 640 DVLOG(1) << "Fetch finished: " << last_status_; |
636 if (!snippets_available_callback_.is_null()) | 641 if (!snippets_available_callback_.is_null()) |
637 snippets_available_callback_.Run(std::move(snippets)); | 642 snippets_available_callback_.Run(std::move(fetched_categories)); |
638 } | 643 } |
639 | 644 |
640 } // namespace ntp_snippets | 645 } // namespace ntp_snippets |
OLD | NEW |