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 120 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
131 std::string GetFetchEndpoint() { | 131 std::string GetFetchEndpoint() { |
132 std::string endpoint = variations::GetVariationParamValue( | 132 std::string endpoint = variations::GetVariationParamValue( |
133 ntp_snippets::kStudyName, kContentSuggestionsBackend); | 133 ntp_snippets::kStudyName, kContentSuggestionsBackend); |
134 return endpoint.empty() ? kChromeReaderServer : endpoint; | 134 return endpoint.empty() ? kChromeReaderServer : endpoint; |
135 } | 135 } |
136 | 136 |
137 bool IsBooleanParameterEnabled(const std::string& param_name, | 137 bool IsBooleanParameterEnabled(const std::string& param_name, |
138 bool default_value) { | 138 bool default_value) { |
139 std::string param_value = variations::GetVariationParamValueByFeature( | 139 std::string param_value = variations::GetVariationParamValueByFeature( |
140 ntp_snippets::kArticleSuggestionsFeature, param_name); | 140 ntp_snippets::kArticleSuggestionsFeature, param_name); |
141 if (param_value == kBooleanParameterEnabled) | 141 if (param_value == kBooleanParameterEnabled) { |
142 return true; | 142 return true; |
143 if (param_value == kBooleanParameterDisabled) | 143 } |
| 144 if (param_value == kBooleanParameterDisabled) { |
144 return false; | 145 return false; |
| 146 } |
145 if (!param_value.empty()) { | 147 if (!param_value.empty()) { |
146 LOG(WARNING) << "Invalid value \"" << param_value | 148 LOG(WARNING) << "Invalid value \"" << param_value |
147 << "\" for variation parameter " << param_name; | 149 << "\" for variation parameter " << param_name; |
148 } | 150 } |
149 return default_value; | 151 return default_value; |
150 } | 152 } |
151 | 153 |
152 bool IsSendingTopLanguagesEnabled() { | 154 bool IsSendingTopLanguagesEnabled() { |
153 return IsBooleanParameterEnabled(kSendTopLanguagesName, false); | 155 return IsBooleanParameterEnabled(kSendTopLanguagesName, false); |
154 } | 156 } |
155 | 157 |
156 bool IsSendingUserClassEnabled() { | 158 bool IsSendingUserClassEnabled() { |
157 return IsBooleanParameterEnabled(kSendUserClassName, false); | 159 return IsBooleanParameterEnabled(kSendUserClassName, false); |
158 } | 160 } |
159 | 161 |
160 bool UsesChromeContentSuggestionsAPI(const GURL& endpoint) { | 162 bool UsesChromeContentSuggestionsAPI(const GURL& endpoint) { |
161 if (endpoint == kChromeReaderServer) | 163 if (endpoint == kChromeReaderServer) { |
162 return false; | 164 return false; |
| 165 } |
163 | 166 |
164 if (endpoint != kContentSuggestionsServer && | 167 if (endpoint != kContentSuggestionsServer && |
165 endpoint != kContentSuggestionsStagingServer && | 168 endpoint != kContentSuggestionsStagingServer && |
166 endpoint != kContentSuggestionsAlphaServer) { | 169 endpoint != kContentSuggestionsAlphaServer) { |
167 LOG(WARNING) << "Unknown value for " << kContentSuggestionsBackend << ": " | 170 LOG(WARNING) << "Unknown value for " << kContentSuggestionsBackend << ": " |
168 << "assuming chromecontentsuggestions-style API"; | 171 << "assuming chromecontentsuggestions-style API"; |
169 } | 172 } |
170 return true; | 173 return true; |
171 } | 174 } |
172 | 175 |
(...skipping 177 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
350 } else { | 353 } else { |
351 personalization_ = Personalization::kBoth; | 354 personalization_ = Personalization::kBoth; |
352 LOG_IF(WARNING, !personalization.empty() && | 355 LOG_IF(WARNING, !personalization.empty() && |
353 personalization != kPersonalizationBothString) | 356 personalization != kPersonalizationBothString) |
354 << "Unknown value for " << kPersonalizationName << ": " | 357 << "Unknown value for " << kPersonalizationName << ": " |
355 << personalization; | 358 << personalization; |
356 } | 359 } |
357 } | 360 } |
358 | 361 |
359 NTPSnippetsFetcher::~NTPSnippetsFetcher() { | 362 NTPSnippetsFetcher::~NTPSnippetsFetcher() { |
360 if (waiting_for_refresh_token_) | 363 if (waiting_for_refresh_token_) { |
361 token_service_->RemoveObserver(this); | 364 token_service_->RemoveObserver(this); |
| 365 } |
362 } | 366 } |
363 | 367 |
364 void NTPSnippetsFetcher::FetchSnippets(const Params& params, | 368 void NTPSnippetsFetcher::FetchSnippets(const Params& params, |
365 SnippetsAvailableCallback callback) { | 369 SnippetsAvailableCallback callback) { |
366 if (!DemandQuotaForRequest(params.interactive_request)) { | 370 if (!DemandQuotaForRequest(params.interactive_request)) { |
367 FetchFinished(OptionalFetchedCategories(), | 371 FetchFinished(OptionalFetchedCategories(), |
368 params.interactive_request | 372 params.interactive_request |
369 ? FetchResult::INTERACTIVE_QUOTA_ERROR | 373 ? FetchResult::INTERACTIVE_QUOTA_ERROR |
370 : FetchResult::NON_INTERACTIVE_QUOTA_ERROR, | 374 : FetchResult::NON_INTERACTIVE_QUOTA_ERROR, |
371 /*extra_message=*/std::string()); | 375 /*extra_message=*/std::string()); |
(...skipping 99 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
471 regular_hosts->AppendString(host); | 475 regular_hosts->AppendString(host); |
472 } | 476 } |
473 request->Set("regularlyVisitedHostNames", std::move(regular_hosts)); | 477 request->Set("regularlyVisitedHostNames", std::move(regular_hosts)); |
474 request->SetString("priority", params.interactive_request | 478 request->SetString("priority", params.interactive_request |
475 ? "USER_ACTION" | 479 ? "USER_ACTION" |
476 : "BACKGROUND_PREFETCH"); | 480 : "BACKGROUND_PREFETCH"); |
477 | 481 |
478 auto excluded = base::MakeUnique<base::ListValue>(); | 482 auto excluded = base::MakeUnique<base::ListValue>(); |
479 for (const auto& id : params.excluded_ids) { | 483 for (const auto& id : params.excluded_ids) { |
480 excluded->AppendString(id); | 484 excluded->AppendString(id); |
481 if (excluded->GetSize() >= kMaxExcludedIds) | 485 if (excluded->GetSize() >= kMaxExcludedIds) { |
482 break; | 486 break; |
| 487 } |
483 } | 488 } |
484 request->Set("excludedSuggestionIds", std::move(excluded)); | 489 request->Set("excludedSuggestionIds", std::move(excluded)); |
485 | 490 |
486 if (!user_class.empty()) | 491 if (!user_class.empty()) { |
487 request->SetString("userActivenessClass", user_class); | 492 request->SetString("userActivenessClass", user_class); |
| 493 } |
488 | 494 |
489 if (ui_language.frequency == 0 && other_top_language.frequency == 0) | 495 if (ui_language.frequency == 0 && other_top_language.frequency == 0) { |
490 break; | 496 break; |
| 497 } |
491 | 498 |
492 auto language_list = base::MakeUnique<base::ListValue>(); | 499 auto language_list = base::MakeUnique<base::ListValue>(); |
493 if (ui_language.frequency > 0) | 500 if (ui_language.frequency > 0) { |
494 AppendLanguageInfoToList(language_list.get(), ui_language); | 501 AppendLanguageInfoToList(language_list.get(), ui_language); |
495 if (other_top_language.frequency > 0) | 502 } |
| 503 if (other_top_language.frequency > 0) { |
496 AppendLanguageInfoToList(language_list.get(), other_top_language); | 504 AppendLanguageInfoToList(language_list.get(), other_top_language); |
| 505 } |
497 request->Set("topLanguages", std::move(language_list)); | 506 request->Set("topLanguages", std::move(language_list)); |
498 | 507 |
499 // TODO(sfiera): Support only_return_personalized_results. | 508 // TODO(sfiera): Support only_return_personalized_results. |
500 // TODO(sfiera): Support count_to_fetch. | 509 // TODO(sfiera): Support count_to_fetch. |
501 break; | 510 break; |
502 } | 511 } |
503 } | 512 } |
504 | 513 |
505 std::string request_json; | 514 std::string request_json; |
506 bool success = base::JSONWriter::WriteWithOptions( | 515 bool success = base::JSONWriter::WriteWithOptions( |
507 *request, base::JSONWriter::OPTIONS_PRETTY_PRINT, &request_json); | 516 *request, base::JSONWriter::OPTIONS_PRETTY_PRINT, &request_json); |
508 DCHECK(success); | 517 DCHECK(success); |
509 return request_json; | 518 return request_json; |
510 } | 519 } |
511 | 520 |
512 void NTPSnippetsFetcher::FetchSnippetsImpl(const GURL& url, | 521 void NTPSnippetsFetcher::FetchSnippetsImpl(const GURL& url, |
513 const std::string& auth_header, | 522 const std::string& auth_header, |
514 const std::string& request) { | 523 const std::string& request) { |
515 url_fetcher_ = URLFetcher::Create(url, URLFetcher::POST, this); | 524 url_fetcher_ = URLFetcher::Create(url, URLFetcher::POST, this); |
516 | 525 |
517 url_fetcher_->SetRequestContext(url_request_context_getter_.get()); | 526 url_fetcher_->SetRequestContext(url_request_context_getter_.get()); |
518 url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | | 527 url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | |
519 net::LOAD_DO_NOT_SAVE_COOKIES); | 528 net::LOAD_DO_NOT_SAVE_COOKIES); |
520 | 529 |
521 data_use_measurement::DataUseUserData::AttachToFetcher( | 530 data_use_measurement::DataUseUserData::AttachToFetcher( |
522 url_fetcher_.get(), data_use_measurement::DataUseUserData::NTP_SNIPPETS); | 531 url_fetcher_.get(), data_use_measurement::DataUseUserData::NTP_SNIPPETS); |
523 | 532 |
524 HttpRequestHeaders headers; | 533 HttpRequestHeaders headers; |
525 if (!auth_header.empty()) | 534 if (!auth_header.empty()) { |
526 headers.SetHeader("Authorization", auth_header); | 535 headers.SetHeader("Authorization", auth_header); |
| 536 } |
527 headers.SetHeader("Content-Type", "application/json; charset=UTF-8"); | 537 headers.SetHeader("Content-Type", "application/json; charset=UTF-8"); |
528 // Add X-Client-Data header with experiment IDs from field trials. | 538 // Add X-Client-Data header with experiment IDs from field trials. |
529 variations::AppendVariationHeaders(url, | 539 variations::AppendVariationHeaders(url, |
530 false, // incognito | 540 false, // incognito |
531 false, // uma_enabled | 541 false, // uma_enabled |
532 &headers); | 542 &headers); |
533 url_fetcher_->SetExtraRequestHeaders(headers.ToString()); | 543 url_fetcher_->SetExtraRequestHeaders(headers.ToString()); |
534 url_fetcher_->SetUploadData("application/json", request); | 544 url_fetcher_->SetUploadData("application/json", request); |
535 // Log the request for debugging network issues. | 545 // Log the request for debugging network issues. |
536 VLOG(1) << "Sending a NTP snippets request to " << url << ":" << std::endl | 546 VLOG(1) << "Sending a NTP snippets request to " << url << ":" << std::endl |
(...skipping 10 matching lines...) Expand all Loading... |
547 return (personalization_ == Personalization::kPersonal || | 557 return (personalization_ == Personalization::kPersonal || |
548 personalization_ == Personalization::kBoth); | 558 personalization_ == Personalization::kBoth); |
549 } | 559 } |
550 | 560 |
551 NTPSnippetsFetcher::RequestBuilder NTPSnippetsFetcher::MakeRequestBuilder() | 561 NTPSnippetsFetcher::RequestBuilder NTPSnippetsFetcher::MakeRequestBuilder() |
552 const { | 562 const { |
553 RequestBuilder result; | 563 RequestBuilder result; |
554 result.params = params_; | 564 result.params = params_; |
555 result.fetch_api = fetch_api_; | 565 result.fetch_api = fetch_api_; |
556 | 566 |
557 if (IsSendingUserClassEnabled()) | 567 if (IsSendingUserClassEnabled()) { |
558 result.user_class = GetUserClassString(user_classifier_->GetUserClass()); | 568 result.user_class = GetUserClassString(user_classifier_->GetUserClass()); |
| 569 } |
559 | 570 |
560 // TODO(jkrcal): Add language model factory for iOS and add fakes to tests so | 571 // TODO(jkrcal): Add language model factory for iOS and add fakes to tests so |
561 // that |language_model_| is never nullptr. Remove this check and add a DCHECK | 572 // that |language_model_| is never nullptr. Remove this check and add a DCHECK |
562 // into the constructor. | 573 // into the constructor. |
563 if (!language_model_ || !IsSendingTopLanguagesEnabled()) | 574 if (!language_model_ || !IsSendingTopLanguagesEnabled()) { |
564 return result; | 575 return result; |
| 576 } |
565 | 577 |
566 // TODO(jkrcal): Is this back-and-forth converting necessary? | 578 // TODO(jkrcal): Is this back-and-forth converting necessary? |
567 result.ui_language.language_code = ISO639FromPosixLocale( | 579 result.ui_language.language_code = ISO639FromPosixLocale( |
568 PosixLocaleFromBCP47Language(result.params.language_code)); | 580 PosixLocaleFromBCP47Language(result.params.language_code)); |
569 result.ui_language.frequency = | 581 result.ui_language.frequency = |
570 language_model_->GetLanguageFrequency(result.ui_language.language_code); | 582 language_model_->GetLanguageFrequency(result.ui_language.language_code); |
571 | 583 |
572 std::vector<LanguageModel::LanguageInfo> top_languages = | 584 std::vector<LanguageModel::LanguageInfo> top_languages = |
573 language_model_->GetTopLanguages(); | 585 language_model_->GetTopLanguages(); |
574 for (const LanguageModel::LanguageInfo& info : top_languages) { | 586 for (const LanguageModel::LanguageInfo& info : top_languages) { |
(...skipping 79 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
654 FetchFinished( | 666 FetchFinished( |
655 OptionalFetchedCategories(), FetchResult::OAUTH_TOKEN_ERROR, | 667 OptionalFetchedCategories(), FetchResult::OAUTH_TOKEN_ERROR, |
656 /*extra_message=*/base::StringPrintf(" (%s)", error.ToString().c_str())); | 668 /*extra_message=*/base::StringPrintf(" (%s)", error.ToString().c_str())); |
657 } | 669 } |
658 | 670 |
659 //////////////////////////////////////////////////////////////////////////////// | 671 //////////////////////////////////////////////////////////////////////////////// |
660 // OAuth2TokenService::Observer overrides | 672 // OAuth2TokenService::Observer overrides |
661 void NTPSnippetsFetcher::OnRefreshTokenAvailable( | 673 void NTPSnippetsFetcher::OnRefreshTokenAvailable( |
662 const std::string& account_id) { | 674 const std::string& account_id) { |
663 // Only react on tokens for the account the user has signed in with. | 675 // Only react on tokens for the account the user has signed in with. |
664 if (account_id != signin_manager_->GetAuthenticatedAccountId()) | 676 if (account_id != signin_manager_->GetAuthenticatedAccountId()) { |
665 return; | 677 return; |
| 678 } |
666 | 679 |
667 token_service_->RemoveObserver(this); | 680 token_service_->RemoveObserver(this); |
668 waiting_for_refresh_token_ = false; | 681 waiting_for_refresh_token_ = false; |
669 oauth_token_retried_ = false; | 682 oauth_token_retried_ = false; |
670 StartTokenRequest(); | 683 StartTokenRequest(); |
671 } | 684 } |
672 | 685 |
673 //////////////////////////////////////////////////////////////////////////////// | 686 //////////////////////////////////////////////////////////////////////////////// |
674 // URLFetcherDelegate overrides | 687 // URLFetcherDelegate overrides |
675 void NTPSnippetsFetcher::OnURLFetchComplete(const URLFetcher* source) { | 688 void NTPSnippetsFetcher::OnURLFetchComplete(const URLFetcher* source) { |
(...skipping 125 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
801 << "): " << last_fetch_json_; | 814 << "): " << last_fetch_json_; |
802 FetchFinished( | 815 FetchFinished( |
803 OptionalFetchedCategories(), FetchResult::JSON_PARSE_ERROR, | 816 OptionalFetchedCategories(), FetchResult::JSON_PARSE_ERROR, |
804 /*extra_message=*/base::StringPrintf(" (error %s)", error.c_str())); | 817 /*extra_message=*/base::StringPrintf(" (error %s)", error.c_str())); |
805 } | 818 } |
806 | 819 |
807 // The response from the backend might include suggestions from multiple | 820 // The response from the backend might include suggestions from multiple |
808 // categories. If only fetches for a single category were requested, this | 821 // categories. If only fetches for a single category were requested, this |
809 // function filters them out. | 822 // function filters them out. |
810 void NTPSnippetsFetcher::FilterCategories(FetchedCategoriesVector* categories) { | 823 void NTPSnippetsFetcher::FilterCategories(FetchedCategoriesVector* categories) { |
811 if (!params_.exclusive_category.has_value()) | 824 if (!params_.exclusive_category.has_value()) { |
812 return; | 825 return; |
| 826 } |
813 Category exclusive = params_.exclusive_category.value(); | 827 Category exclusive = params_.exclusive_category.value(); |
814 auto category_it = | 828 auto category_it = |
815 std::find_if(categories->begin(), categories->end(), | 829 std::find_if(categories->begin(), categories->end(), |
816 [&exclusive](const FetchedCategory& c) -> bool { | 830 [&exclusive](const FetchedCategory& c) -> bool { |
817 return c.category == exclusive; | 831 return c.category == exclusive; |
818 }); | 832 }); |
819 if (category_it == categories->end()) { | 833 if (category_it == categories->end()) { |
820 categories->clear(); | 834 categories->clear(); |
821 return; | 835 return; |
822 } | 836 } |
823 FetchedCategory category = std::move(*category_it); | 837 FetchedCategory category = std::move(*category_it); |
824 categories->clear(); | 838 categories->clear(); |
825 categories->emplace_back(std::move(category)); | 839 categories->emplace_back(std::move(category)); |
826 } | 840 } |
827 | 841 |
828 void NTPSnippetsFetcher::FetchFinished( | 842 void NTPSnippetsFetcher::FetchFinished( |
829 OptionalFetchedCategories fetched_categories, | 843 OptionalFetchedCategories fetched_categories, |
830 FetchResult result, | 844 FetchResult result, |
831 const std::string& extra_message) { | 845 const std::string& extra_message) { |
832 DCHECK(result == FetchResult::SUCCESS || !fetched_categories); | 846 DCHECK(result == FetchResult::SUCCESS || !fetched_categories); |
833 last_status_ = FetchResultToString(result) + extra_message; | 847 last_status_ = FetchResultToString(result) + extra_message; |
834 | 848 |
835 // Filter out unwanted categories if necessary. | 849 // Filter out unwanted categories if necessary. |
836 // TODO(fhorschig): As soon as the server supports filtering by | 850 // TODO(fhorschig): As soon as the server supports filtering by |
837 // that instead of over-fetching and filtering here. | 851 // that instead of over-fetching and filtering here. |
838 if (fetched_categories.has_value()) | 852 if (fetched_categories.has_value()) { |
839 FilterCategories(&fetched_categories.value()); | 853 FilterCategories(&fetched_categories.value()); |
| 854 } |
840 | 855 |
841 // Don't record FetchTimes if the result indicates that a precondition | 856 // Don't record FetchTimes if the result indicates that a precondition |
842 // failed and we never actually sent a network request | 857 // failed and we never actually sent a network request |
843 if (!IsFetchPreconditionFailed(result)) { | 858 if (!IsFetchPreconditionFailed(result)) { |
844 UMA_HISTOGRAM_TIMES("NewTabPage.Snippets.FetchTime", | 859 UMA_HISTOGRAM_TIMES("NewTabPage.Snippets.FetchTime", |
845 tick_clock_->NowTicks() - fetch_start_time_); | 860 tick_clock_->NowTicks() - fetch_start_time_); |
846 } | 861 } |
847 UMA_HISTOGRAM_ENUMERATION("NewTabPage.Snippets.FetchResult", | 862 UMA_HISTOGRAM_ENUMERATION("NewTabPage.Snippets.FetchResult", |
848 static_cast<int>(result), | 863 static_cast<int>(result), |
849 static_cast<int>(FetchResult::RESULT_MAX)); | 864 static_cast<int>(FetchResult::RESULT_MAX)); |
850 | 865 |
851 DVLOG(1) << "Fetch finished: " << last_status_; | 866 DVLOG(1) << "Fetch finished: " << last_status_; |
852 if (!snippets_available_callback_.is_null()) | 867 if (!snippets_available_callback_.is_null()) { |
853 std::move(snippets_available_callback_).Run(std::move(fetched_categories)); | 868 std::move(snippets_available_callback_).Run(std::move(fetched_categories)); |
| 869 } |
854 } | 870 } |
855 | 871 |
856 bool NTPSnippetsFetcher::DemandQuotaForRequest(bool interactive_request) { | 872 bool NTPSnippetsFetcher::DemandQuotaForRequest(bool interactive_request) { |
857 switch (user_classifier_->GetUserClass()) { | 873 switch (user_classifier_->GetUserClass()) { |
858 case UserClassifier::UserClass::RARE_NTP_USER: | 874 case UserClassifier::UserClass::RARE_NTP_USER: |
859 return request_throttler_rare_ntp_user_.DemandQuotaForRequest( | 875 return request_throttler_rare_ntp_user_.DemandQuotaForRequest( |
860 interactive_request); | 876 interactive_request); |
861 case UserClassifier::UserClass::ACTIVE_NTP_USER: | 877 case UserClassifier::UserClass::ACTIVE_NTP_USER: |
862 return request_throttler_active_ntp_user_.DemandQuotaForRequest( | 878 return request_throttler_active_ntp_user_.DemandQuotaForRequest( |
863 interactive_request); | 879 interactive_request); |
864 case UserClassifier::UserClass::ACTIVE_SUGGESTIONS_CONSUMER: | 880 case UserClassifier::UserClass::ACTIVE_SUGGESTIONS_CONSUMER: |
865 return request_throttler_active_suggestions_consumer_ | 881 return request_throttler_active_suggestions_consumer_ |
866 .DemandQuotaForRequest(interactive_request); | 882 .DemandQuotaForRequest(interactive_request); |
867 } | 883 } |
868 NOTREACHED(); | 884 NOTREACHED(); |
869 return false; | 885 return false; |
870 } | 886 } |
871 | 887 |
872 } // namespace ntp_snippets | 888 } // namespace ntp_snippets |
OLD | NEW |