Chromium Code Reviews| 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/ntp_snippets_fetcher.h" | 5 #include "components/ntp_snippets/ntp_snippets_fetcher.h" |
| 6 | 6 |
| 7 #include <stdlib.h> | 7 #include <stdlib.h> |
| 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" |
| 11 #include "base/files/file_util.h" | 11 #include "base/files/file_util.h" |
| 12 #include "base/json/json_writer.h" | |
| 13 #include "base/memory/ptr_util.h" | |
| 12 #include "base/metrics/histogram_macros.h" | 14 #include "base/metrics/histogram_macros.h" |
| 13 #include "base/metrics/sparse_histogram.h" | 15 #include "base/metrics/sparse_histogram.h" |
| 14 #include "base/path_service.h" | 16 #include "base/path_service.h" |
| 15 #include "base/strings/string_number_conversions.h" | 17 #include "base/strings/string_number_conversions.h" |
| 16 #include "base/strings/string_util.h" | 18 #include "base/strings/string_util.h" |
| 17 #include "base/strings/stringprintf.h" | 19 #include "base/strings/stringprintf.h" |
| 18 #include "base/time/default_tick_clock.h" | 20 #include "base/time/default_tick_clock.h" |
| 19 #include "base/values.h" | 21 #include "base/values.h" |
| 20 #include "components/data_use_measurement/core/data_use_user_data.h" | 22 #include "components/data_use_measurement/core/data_use_user_data.h" |
| 21 #include "components/ntp_snippets/ntp_snippets_constants.h" | 23 #include "components/ntp_snippets/ntp_snippets_constants.h" |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 55 | 57 |
| 56 // Constants for possible values of the "fetching_personalization" parameter. | 58 // Constants for possible values of the "fetching_personalization" parameter. |
| 57 const char kPersonalizationPersonalString[] = "personal"; | 59 const char kPersonalizationPersonalString[] = "personal"; |
| 58 const char kPersonalizationNonPersonalString[] = "non_personal"; | 60 const char kPersonalizationNonPersonalString[] = "non_personal"; |
| 59 const char kPersonalizationBothString[] = "both"; // the default value | 61 const char kPersonalizationBothString[] = "both"; // the default value |
| 60 | 62 |
| 61 // Constants for possible values of the "fetching_host_restrict" parameter. | 63 // Constants for possible values of the "fetching_host_restrict" parameter. |
| 62 const char kHostRestrictionOnString[] = "on"; // the default value | 64 const char kHostRestrictionOnString[] = "on"; // the default value |
| 63 const char kHostRestrictionOffString[] = "off"; | 65 const char kHostRestrictionOffString[] = "off"; |
| 64 | 66 |
| 65 const char kRequestFormat[] = | |
| 66 "{" | |
| 67 " \"response_detail_level\": \"STANDARD\"," | |
| 68 "%s" // If authenticated - an obfuscated Gaia ID will be inserted here. | |
| 69 " \"advanced_options\": {" | |
| 70 " \"local_scoring_params\": {" | |
| 71 " \"content_params\": {" | |
| 72 " \"only_return_personalized_results\": %s" | |
| 73 "%s" // If authenticated - user segment (lang code) will be inserted here. | |
| 74 " }," | |
| 75 " \"content_restricts\": [" | |
| 76 " {" | |
| 77 " \"type\": \"METADATA\"," | |
| 78 " \"value\": \"TITLE\"" | |
| 79 " }," | |
| 80 " {" | |
| 81 " \"type\": \"METADATA\"," | |
| 82 " \"value\": \"SNIPPET\"" | |
| 83 " }," | |
| 84 " {" | |
| 85 " \"type\": \"METADATA\"," | |
| 86 " \"value\": \"THUMBNAIL\"" | |
| 87 " }" | |
| 88 " ]," | |
| 89 " \"content_selectors\": [%s]" | |
| 90 " }," | |
| 91 " \"global_scoring_params\": {" | |
| 92 " \"num_to_return\": %i," | |
| 93 " \"sort_type\": 1" | |
| 94 " }" | |
| 95 " }" | |
| 96 "}"; | |
| 97 | |
| 98 const char kGaiaIdFormat[] = " \"obfuscated_gaia_id\": \"%s\","; | |
| 99 const char kUserSegmentFormat[] = " ,\"user_segment\": \"%s\""; | |
| 100 const char kHostRestrictFormat[] = | |
| 101 " {" | |
| 102 " \"type\": \"HOST_RESTRICT\"," | |
| 103 " \"value\": \"%s\"" | |
| 104 " }"; | |
| 105 const char kTrueString[] = "true"; | |
| 106 const char kFalseString[] = "false"; | |
| 107 | |
| 108 std::string FetchResultToString(NTPSnippetsFetcher::FetchResult result) { | 67 std::string FetchResultToString(NTPSnippetsFetcher::FetchResult result) { |
| 109 switch (result) { | 68 switch (result) { |
| 110 case NTPSnippetsFetcher::FetchResult::SUCCESS: | 69 case NTPSnippetsFetcher::FetchResult::SUCCESS: |
| 111 return "OK"; | 70 return "OK"; |
| 112 case NTPSnippetsFetcher::FetchResult::EMPTY_HOSTS: | 71 case NTPSnippetsFetcher::FetchResult::EMPTY_HOSTS: |
| 113 return "Cannot fetch for empty hosts list."; | 72 return "Cannot fetch for empty hosts list."; |
| 114 case NTPSnippetsFetcher::FetchResult::URL_REQUEST_STATUS_ERROR: | 73 case NTPSnippetsFetcher::FetchResult::URL_REQUEST_STATUS_ERROR: |
| 115 return "URLRequestStatus error"; | 74 return "URLRequestStatus error"; |
| 116 case NTPSnippetsFetcher::FetchResult::HTTP_ERROR: | 75 case NTPSnippetsFetcher::FetchResult::HTTP_ERROR: |
| 117 return "HTTP error"; | 76 return "HTTP error"; |
| 118 case NTPSnippetsFetcher::FetchResult::JSON_PARSE_ERROR: | 77 case NTPSnippetsFetcher::FetchResult::JSON_PARSE_ERROR: |
| 119 return "Received invalid JSON"; | 78 return "Received invalid JSON"; |
| 120 case NTPSnippetsFetcher::FetchResult::INVALID_SNIPPET_CONTENT_ERROR: | 79 case NTPSnippetsFetcher::FetchResult::INVALID_SNIPPET_CONTENT_ERROR: |
| 121 return "Invalid / empty list."; | 80 return "Invalid / empty list."; |
| 122 case NTPSnippetsFetcher::FetchResult::OAUTH_TOKEN_ERROR: | 81 case NTPSnippetsFetcher::FetchResult::OAUTH_TOKEN_ERROR: |
| 123 return "Error in obtaining an OAuth2 access token."; | 82 return "Error in obtaining an OAuth2 access token."; |
| 124 case NTPSnippetsFetcher::FetchResult::RESULT_MAX: | 83 case NTPSnippetsFetcher::FetchResult::RESULT_MAX: |
| 125 break; | 84 break; |
| 126 } | 85 } |
| 127 NOTREACHED(); | 86 NOTREACHED(); |
| 128 return "Unknown error"; | 87 return "Unknown error"; |
| 129 } | 88 } |
| 130 | 89 |
| 131 std::string BuildRequest(const std::string& obfuscated_gaia_id, | |
| 132 bool only_return_personalized_results, | |
| 133 const std::string& user_segment, | |
| 134 const std::string& host_restricts, | |
| 135 int count_to_fetch) { | |
| 136 return base::StringPrintf( | |
| 137 kRequestFormat, obfuscated_gaia_id.c_str(), | |
| 138 only_return_personalized_results ? kTrueString : kFalseString, | |
| 139 user_segment.c_str(), host_restricts.c_str(), count_to_fetch); | |
| 140 } | |
| 141 | |
| 142 } // namespace | 90 } // namespace |
| 143 | 91 |
| 144 NTPSnippetsFetcher::NTPSnippetsFetcher( | 92 NTPSnippetsFetcher::NTPSnippetsFetcher( |
| 145 SigninManagerBase* signin_manager, | 93 SigninManagerBase* signin_manager, |
| 146 OAuth2TokenService* token_service, | 94 OAuth2TokenService* token_service, |
| 147 scoped_refptr<URLRequestContextGetter> url_request_context_getter, | 95 scoped_refptr<URLRequestContextGetter> url_request_context_getter, |
| 148 const ParseJSONCallback& parse_json_callback, | 96 const ParseJSONCallback& parse_json_callback, |
| 149 bool is_stable_channel) | 97 bool is_stable_channel) |
| 150 : OAuth2TokenService::Consumer("ntp_snippets"), | 98 : OAuth2TokenService::Consumer("ntp_snippets"), |
| 151 signin_manager_(signin_manager), | 99 signin_manager_(signin_manager), |
| (...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 230 // Wait until we get a refresh token. | 178 // Wait until we get a refresh token. |
| 231 waiting_for_refresh_token_ = true; | 179 waiting_for_refresh_token_ = true; |
| 232 token_service_->AddObserver(this); | 180 token_service_->AddObserver(this); |
| 233 } | 181 } |
| 234 } else { | 182 } else { |
| 235 // Not signed in: fetch snippets (without authentication). | 183 // Not signed in: fetch snippets (without authentication). |
| 236 FetchSnippetsNonAuthenticated(); | 184 FetchSnippetsNonAuthenticated(); |
| 237 } | 185 } |
| 238 } | 186 } |
| 239 | 187 |
| 188 // static | |
| 189 std::string NTPSnippetsFetcher::BuildRequest( | |
| 190 const std::string& obfuscated_gaia_id, | |
| 191 bool only_return_personalized_results, | |
| 192 const std::string& user_segment, | |
| 193 const std::set<std::string>& host_restricts, | |
| 194 int count_to_fetch) { | |
| 195 auto content_params = base::MakeUnique<base::DictionaryValue>(); | |
| 196 content_params->SetBoolean("only_return_personalized_results", | |
| 197 only_return_personalized_results); | |
| 198 if (!user_segment.empty()) { | |
| 199 content_params->SetString("user_segment", user_segment); | |
| 200 } | |
| 201 | |
| 202 auto content_restricts = base::MakeUnique<base::ListValue>(); | |
| 203 for (const auto& metadata : {"TITLE", "SNIPPET", "THUMBNAIL"}) { | |
| 204 std::unique_ptr<base::DictionaryValue> entry(new base::DictionaryValue); | |
|
Marc Treib
2016/06/17 15:28:09
Any reason this doesn't use the "auto var = MakeUn
sfiera
2016/06/20 10:21:52
I think I wrote it before Bernhard enlightened me
| |
| 205 entry->SetString("type", "METADATA"); | |
| 206 entry->SetString("value", metadata); | |
| 207 content_restricts->Append(std::move(entry)); | |
| 208 } | |
| 209 | |
| 210 auto content_selectors = base::MakeUnique<base::ListValue>(); | |
| 211 for (const auto& host : host_restricts) { | |
| 212 std::unique_ptr<base::DictionaryValue> entry(new base::DictionaryValue); | |
|
Marc Treib
2016/06/17 15:28:09
Also here.
sfiera
2016/06/20 10:21:52
and copy-pasted it below. Both fixed.
| |
| 213 entry->SetString("type", "HOST_RESTRICT"); | |
| 214 entry->SetString("value", host); | |
| 215 content_selectors->Append(std::move(entry)); | |
| 216 } | |
| 217 | |
| 218 auto local_scoring_params = base::MakeUnique<base::DictionaryValue>(); | |
| 219 local_scoring_params->Set("content_params", std::move(content_params)); | |
| 220 local_scoring_params->Set("content_restricts", std::move(content_restricts)); | |
| 221 local_scoring_params->Set("content_selectors", std::move(content_selectors)); | |
| 222 | |
| 223 auto global_scoring_params = base::MakeUnique<base::DictionaryValue>(); | |
| 224 global_scoring_params->SetInteger("num_to_return", count_to_fetch); | |
| 225 global_scoring_params->SetInteger("sort_type", 1); | |
| 226 | |
| 227 auto advanced = base::MakeUnique<base::DictionaryValue>(); | |
| 228 advanced->Set("local_scoring_params", std::move(local_scoring_params)); | |
| 229 advanced->Set("global_scoring_params", std::move(global_scoring_params)); | |
| 230 | |
| 231 auto request = base::MakeUnique<base::DictionaryValue>(); | |
| 232 request->SetString("response_detail_level", "STANDARD"); | |
| 233 request->Set("advanced_options", std::move(advanced)); | |
| 234 if (!obfuscated_gaia_id.empty()) { | |
| 235 request->SetString("obfuscated_gaia_id", obfuscated_gaia_id); | |
| 236 } | |
| 237 | |
| 238 std::string request_json; | |
| 239 DCHECK(base::JSONWriter::WriteWithOptions( | |
|
Marc Treib
2016/06/17 15:28:09
The content of the DCHECK will only be executed in
sfiera
2016/06/20 10:21:52
Done.
| |
| 240 *request, base::JSONWriter::OPTIONS_PRETTY_PRINT, &request_json)); | |
| 241 return request_json; | |
| 242 } | |
| 243 | |
| 240 void NTPSnippetsFetcher::FetchSnippetsImpl(const GURL& url, | 244 void NTPSnippetsFetcher::FetchSnippetsImpl(const GURL& url, |
| 241 const std::string& auth_header, | 245 const std::string& auth_header, |
| 242 const std::string& request) { | 246 const std::string& request) { |
| 243 url_fetcher_ = URLFetcher::Create(url, URLFetcher::POST, this); | 247 url_fetcher_ = URLFetcher::Create(url, URLFetcher::POST, this); |
| 244 | 248 |
| 245 url_fetcher_->SetRequestContext(url_request_context_getter_.get()); | 249 url_fetcher_->SetRequestContext(url_request_context_getter_.get()); |
| 246 url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | | 250 url_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SEND_COOKIES | |
| 247 net::LOAD_DO_NOT_SAVE_COOKIES); | 251 net::LOAD_DO_NOT_SAVE_COOKIES); |
| 248 | 252 |
| 249 data_use_measurement::DataUseUserData::AttachToFetcher( | 253 data_use_measurement::DataUseUserData::AttachToFetcher( |
| 250 url_fetcher_.get(), data_use_measurement::DataUseUserData::NTP_SNIPPETS); | 254 url_fetcher_.get(), data_use_measurement::DataUseUserData::NTP_SNIPPETS); |
| 251 | 255 |
| 252 HttpRequestHeaders headers; | 256 HttpRequestHeaders headers; |
| 253 if (!auth_header.empty()) | 257 if (!auth_header.empty()) |
| 254 headers.SetHeader("Authorization", auth_header); | 258 headers.SetHeader("Authorization", auth_header); |
| 255 headers.SetHeader("Content-Type", "application/json; charset=UTF-8"); | 259 headers.SetHeader("Content-Type", "application/json; charset=UTF-8"); |
| 256 url_fetcher_->SetExtraRequestHeaders(headers.ToString()); | 260 url_fetcher_->SetExtraRequestHeaders(headers.ToString()); |
| 257 url_fetcher_->SetUploadData("application/json", request); | 261 url_fetcher_->SetUploadData("application/json", request); |
| 258 // Fetchers are sometimes cancelled because a network change was detected. | 262 // Fetchers are sometimes cancelled because a network change was detected. |
| 259 url_fetcher_->SetAutomaticallyRetryOnNetworkChanges(3); | 263 url_fetcher_->SetAutomaticallyRetryOnNetworkChanges(3); |
| 260 // Try to make fetching the files bit more robust even with poor connection. | 264 // Try to make fetching the files bit more robust even with poor connection. |
| 261 url_fetcher_->SetMaxRetriesOn5xx(3); | 265 url_fetcher_->SetMaxRetriesOn5xx(3); |
| 262 url_fetcher_->Start(); | 266 url_fetcher_->Start(); |
| 263 } | 267 } |
| 264 | 268 |
| 265 std::string NTPSnippetsFetcher::GetHostRestricts() const { | |
| 266 std::string host_restricts; | |
| 267 if (UsesHostRestrictions()) { | |
| 268 for (const std::string& host : hosts_) { | |
| 269 if (!host_restricts.empty()) | |
| 270 host_restricts.push_back(','); | |
| 271 host_restricts += base::StringPrintf(kHostRestrictFormat, host.c_str()); | |
| 272 } | |
| 273 } | |
| 274 return host_restricts; | |
| 275 } | |
| 276 | |
| 277 bool NTPSnippetsFetcher::UsesHostRestrictions() const { | 269 bool NTPSnippetsFetcher::UsesHostRestrictions() const { |
| 278 return use_host_restriction_ && | 270 return use_host_restriction_ && |
| 279 !base::CommandLine::ForCurrentProcess()->HasSwitch( | 271 !base::CommandLine::ForCurrentProcess()->HasSwitch( |
| 280 switches::kDontRestrict); | 272 switches::kDontRestrict); |
| 281 } | 273 } |
| 282 | 274 |
| 283 bool NTPSnippetsFetcher::UsesAuthentication() const { | 275 bool NTPSnippetsFetcher::UsesAuthentication() const { |
| 284 return (personalization_ == Personalization::kPersonal || | 276 return (personalization_ == Personalization::kPersonal || |
| 285 personalization_ == Personalization::kBoth); | 277 personalization_ == Personalization::kBoth); |
| 286 } | 278 } |
| 287 | 279 |
| 288 void NTPSnippetsFetcher::FetchSnippetsNonAuthenticated() { | 280 void NTPSnippetsFetcher::FetchSnippetsNonAuthenticated() { |
| 289 // When not providing OAuth token, we need to pass the Google API key. | 281 // When not providing OAuth token, we need to pass the Google API key. |
| 290 const std::string& key = is_stable_channel_ | 282 const std::string& key = is_stable_channel_ |
| 291 ? google_apis::GetAPIKey() | 283 ? google_apis::GetAPIKey() |
| 292 : google_apis::GetNonStableAPIKey(); | 284 : google_apis::GetNonStableAPIKey(); |
| 293 GURL url(base::StringPrintf(kSnippetsServerNonAuthorizedFormat, | 285 GURL url(base::StringPrintf(kSnippetsServerNonAuthorizedFormat, |
| 294 kSnippetsServer, key.c_str())); | 286 kSnippetsServer, key.c_str())); |
| 295 | 287 |
| 296 FetchSnippetsImpl(url, std::string(), | 288 FetchSnippetsImpl( |
| 297 BuildRequest(/*obfuscated_gaia_id=*/std::string(), | 289 url, std::string(), |
| 298 /*only_return_personalized_results=*/false, | 290 BuildRequest(/*obfuscated_gaia_id=*/std::string(), |
| 299 /*user_segment=*/std::string(), | 291 /*only_return_personalized_results=*/false, |
| 300 GetHostRestricts(), count_to_fetch_)); | 292 /*user_segment=*/std::string(), |
| 293 UsesHostRestrictions() ? hosts_ : std::set<std::string>(), | |
| 294 count_to_fetch_)); | |
| 301 } | 295 } |
| 302 | 296 |
| 303 void NTPSnippetsFetcher::FetchSnippetsAuthenticated( | 297 void NTPSnippetsFetcher::FetchSnippetsAuthenticated( |
| 304 const std::string& account_id, | 298 const std::string& account_id, |
| 305 const std::string& oauth_access_token) { | 299 const std::string& oauth_access_token) { |
| 306 std::string gaia_id = base::StringPrintf(kGaiaIdFormat, account_id.c_str()); | |
| 307 std::string user_segment = | |
| 308 base::StringPrintf(kUserSegmentFormat, locale_.c_str()); | |
| 309 | |
| 310 FetchSnippetsImpl( | 300 FetchSnippetsImpl( |
| 311 GURL(kSnippetsServer), | 301 GURL(kSnippetsServer), |
| 312 base::StringPrintf(kAuthorizationRequestHeaderFormat, | 302 base::StringPrintf(kAuthorizationRequestHeaderFormat, |
| 313 oauth_access_token.c_str()), | 303 oauth_access_token.c_str()), |
| 314 BuildRequest(gaia_id, personalization_ == Personalization::kPersonal, | 304 BuildRequest(account_id, personalization_ == Personalization::kPersonal, |
| 315 user_segment, GetHostRestricts(), count_to_fetch_)); | 305 locale_, |
| 306 UsesHostRestrictions() ? hosts_ : std::set<std::string>(), | |
| 307 count_to_fetch_)); | |
| 316 } | 308 } |
| 317 | 309 |
| 318 void NTPSnippetsFetcher::StartTokenRequest() { | 310 void NTPSnippetsFetcher::StartTokenRequest() { |
| 319 OAuth2TokenService::ScopeSet scopes; | 311 OAuth2TokenService::ScopeSet scopes; |
| 320 scopes.insert(kApiScope); | 312 scopes.insert(kApiScope); |
| 321 oauth_request_ = token_service_->StartRequest( | 313 oauth_request_ = token_service_->StartRequest( |
| 322 signin_manager_->GetAuthenticatedAccountId(), scopes, this); | 314 signin_manager_->GetAuthenticatedAccountId(), scopes, this); |
| 323 } | 315 } |
| 324 | 316 |
| 325 //////////////////////////////////////////////////////////////////////////////// | 317 //////////////////////////////////////////////////////////////////////////////// |
| (...skipping 107 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 433 tick_clock_->NowTicks() - fetch_start_time_); | 425 tick_clock_->NowTicks() - fetch_start_time_); |
| 434 UMA_HISTOGRAM_ENUMERATION("NewTabPage.Snippets.FetchResult", | 426 UMA_HISTOGRAM_ENUMERATION("NewTabPage.Snippets.FetchResult", |
| 435 static_cast<int>(result), | 427 static_cast<int>(result), |
| 436 static_cast<int>(FetchResult::RESULT_MAX)); | 428 static_cast<int>(FetchResult::RESULT_MAX)); |
| 437 | 429 |
| 438 if (!snippets_available_callback_.is_null()) | 430 if (!snippets_available_callback_.is_null()) |
| 439 snippets_available_callback_.Run(std::move(snippets)); | 431 snippets_available_callback_.Run(std::move(snippets)); |
| 440 } | 432 } |
| 441 | 433 |
| 442 } // namespace ntp_snippets | 434 } // namespace ntp_snippets |
| OLD | NEW |