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

Side by Side Diff: components/ntp_snippets/ntp_snippets_fetcher.cc

Issue 2077973002: Generate snippets request JSON with base::Value. (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add unit test for BuildRequest(). 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 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
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
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
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
OLDNEW
« no previous file with comments | « components/ntp_snippets/ntp_snippets_fetcher.h ('k') | components/ntp_snippets/ntp_snippets_fetcher_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698