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

Side by Side Diff: components/ntp_snippets/remote/remote_suggestions_fetcher.cc

Issue 2771713003: RemoteSuggestionsFetcher: Use common AccessTokenFetcher helper class (Closed)
Patch Set: Created 3 years, 9 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/remote/remote_suggestions_fetcher.h" 5 #include "components/ntp_snippets/remote/remote_suggestions_fetcher.h"
6 6
7 #include <cstdlib> 7 #include <cstdlib>
8 #include <utility> 8 #include <utility>
9 9
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/memory/ptr_util.h" 12 #include "base/memory/ptr_util.h"
13 #include "base/metrics/histogram_macros.h" 13 #include "base/metrics/histogram_macros.h"
14 #include "base/metrics/sparse_histogram.h" 14 #include "base/metrics/sparse_histogram.h"
15 #include "base/path_service.h" 15 #include "base/path_service.h"
16 #include "base/strings/stringprintf.h" 16 #include "base/strings/stringprintf.h"
17 #include "base/strings/utf_string_conversions.h" 17 #include "base/strings/utf_string_conversions.h"
18 #include "base/time/default_clock.h" 18 #include "base/time/default_clock.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 "components/data_use_measurement/core/data_use_user_data.h" 21 #include "components/data_use_measurement/core/data_use_user_data.h"
22 #include "components/ntp_snippets/category.h" 22 #include "components/ntp_snippets/category.h"
23 #include "components/ntp_snippets/features.h" 23 #include "components/ntp_snippets/features.h"
24 #include "components/ntp_snippets/ntp_snippets_constants.h" 24 #include "components/ntp_snippets/ntp_snippets_constants.h"
25 #include "components/ntp_snippets/remote/request_params.h" 25 #include "components/ntp_snippets/remote/request_params.h"
26 #include "components/ntp_snippets/user_classifier.h" 26 #include "components/ntp_snippets/user_classifier.h"
27 #include "components/signin/core/browser/access_token_fetcher.h"
27 #include "components/signin/core/browser/signin_manager.h" 28 #include "components/signin/core/browser/signin_manager.h"
28 #include "components/signin/core/browser/signin_manager_base.h" 29 #include "components/signin/core/browser/signin_manager_base.h"
29 #include "components/strings/grit/components_strings.h" 30 #include "components/strings/grit/components_strings.h"
30 #include "components/variations/variations_associated_data.h" 31 #include "components/variations/variations_associated_data.h"
31 #include "net/url_request/url_fetcher.h" 32 #include "net/url_request/url_fetcher.h"
32 #include "ui/base/l10n/l10n_util.h" 33 #include "ui/base/l10n/l10n_util.h"
33 34
34 using net::URLFetcher; 35 using net::URLFetcher;
35 using net::URLRequestContextGetter; 36 using net::URLRequestContextGetter;
36 using net::HttpRequestHeaders; 37 using net::HttpRequestHeaders;
(...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after
236 RemoteSuggestionsFetcher::RemoteSuggestionsFetcher( 237 RemoteSuggestionsFetcher::RemoteSuggestionsFetcher(
237 SigninManagerBase* signin_manager, 238 SigninManagerBase* signin_manager,
238 OAuth2TokenService* token_service, 239 OAuth2TokenService* token_service,
239 scoped_refptr<URLRequestContextGetter> url_request_context_getter, 240 scoped_refptr<URLRequestContextGetter> url_request_context_getter,
240 PrefService* pref_service, 241 PrefService* pref_service,
241 LanguageModel* language_model, 242 LanguageModel* language_model,
242 const ParseJSONCallback& parse_json_callback, 243 const ParseJSONCallback& parse_json_callback,
243 const GURL& api_endpoint, 244 const GURL& api_endpoint,
244 const std::string& api_key, 245 const std::string& api_key,
245 const UserClassifier* user_classifier) 246 const UserClassifier* user_classifier)
246 : OAuth2TokenService::Consumer("ntp_snippets"), 247 : signin_manager_(signin_manager),
247 signin_manager_(signin_manager),
248 token_service_(token_service), 248 token_service_(token_service),
249 url_request_context_getter_(std::move(url_request_context_getter)), 249 url_request_context_getter_(std::move(url_request_context_getter)),
250 language_model_(language_model), 250 language_model_(language_model),
251 parse_json_callback_(parse_json_callback), 251 parse_json_callback_(parse_json_callback),
252 fetch_url_(api_endpoint), 252 fetch_url_(api_endpoint),
253 api_key_(api_key), 253 api_key_(api_key),
254 clock_(new base::DefaultClock()), 254 clock_(new base::DefaultClock()),
255 user_classifier_(user_classifier) {} 255 user_classifier_(user_classifier) {}
256 256
257 RemoteSuggestionsFetcher::~RemoteSuggestionsFetcher() { 257 RemoteSuggestionsFetcher::~RemoteSuggestionsFetcher() = default;
258 if (waiting_for_refresh_token_) {
259 token_service_->RemoveObserver(this);
260 }
261 }
262 258
263 void RemoteSuggestionsFetcher::FetchSnippets( 259 void RemoteSuggestionsFetcher::FetchSnippets(
264 const RequestParams& params, 260 const RequestParams& params,
265 SnippetsAvailableCallback callback) { 261 SnippetsAvailableCallback callback) {
266 if (!params.interactive_request) { 262 if (!params.interactive_request) {
267 UMA_HISTOGRAM_SPARSE_SLOWLY( 263 UMA_HISTOGRAM_SPARSE_SLOWLY(
268 "NewTabPage.Snippets.FetchTimeLocal", 264 "NewTabPage.Snippets.FetchTimeLocal",
269 GetMinuteOfTheDay(/*local_time=*/true, 265 GetMinuteOfTheDay(/*local_time=*/true,
270 /*reduced_resolution=*/true, clock_.get())); 266 /*reduced_resolution=*/true, clock_.get()));
271 UMA_HISTOGRAM_SPARSE_SLOWLY( 267 UMA_HISTOGRAM_SPARSE_SLOWLY(
272 "NewTabPage.Snippets.FetchTimeUTC", 268 "NewTabPage.Snippets.FetchTimeUTC",
273 GetMinuteOfTheDay(/*local_time=*/false, 269 GetMinuteOfTheDay(/*local_time=*/false,
274 /*reduced_resolution=*/true, clock_.get())); 270 /*reduced_resolution=*/true, clock_.get()));
275 } 271 }
276 272
277 JsonRequest::Builder builder; 273 JsonRequest::Builder builder;
278 builder.SetLanguageModel(language_model_) 274 builder.SetLanguageModel(language_model_)
279 .SetParams(params) 275 .SetParams(params)
280 .SetParseJsonCallback(parse_json_callback_) 276 .SetParseJsonCallback(parse_json_callback_)
281 .SetClock(clock_.get()) 277 .SetClock(clock_.get())
282 .SetUrlRequestContextGetter(url_request_context_getter_) 278 .SetUrlRequestContextGetter(url_request_context_getter_)
283 .SetUserClassifier(*user_classifier_); 279 .SetUserClassifier(*user_classifier_);
284 280
285 if (signin_manager_->IsAuthenticated()) { 281 if (signin_manager_->IsAuthenticated()) {
286 // Signed-in: get OAuth token --> fetch suggestions. 282 // Signed-in: get OAuth token --> fetch suggestions.
287 oauth_token_retried_ = false;
288 pending_requests_.emplace(std::move(builder), std::move(callback)); 283 pending_requests_.emplace(std::move(builder), std::move(callback));
289 StartTokenRequest(); 284 StartTokenRequest();
290 } else if (signin_manager_->AuthInProgress()) {
Marc Treib 2017/03/23 19:23:19 Do you remember if we had actual proof that this c
jkrcal 2017/03/24 09:09:26 The question is: how does it behave on iOS? Unles
Marc Treib 2017/03/27 08:08:20 Alright, makes sense, at least until we've investi
291 // Currently signing in: wait for auth to finish (the refresh token) -->
292 // get OAuth token --> fetch suggestions.
293 pending_requests_.emplace(std::move(builder), std::move(callback));
294 if (!waiting_for_refresh_token_) {
295 // Wait until we get a refresh token.
296 waiting_for_refresh_token_ = true;
297 token_service_->AddObserver(this);
298 }
299 } else { 285 } else {
300 // Not signed in: fetch suggestions (without authentication). 286 // Not signed in: fetch suggestions (without authentication).
301 FetchSnippetsNonAuthenticated(std::move(builder), std::move(callback)); 287 FetchSnippetsNonAuthenticated(std::move(builder), std::move(callback));
302 } 288 }
303 } 289 }
304 290
305 void RemoteSuggestionsFetcher::FetchSnippetsNonAuthenticated( 291 void RemoteSuggestionsFetcher::FetchSnippetsNonAuthenticated(
306 JsonRequest::Builder builder, 292 JsonRequest::Builder builder,
307 SnippetsAvailableCallback callback) { 293 SnippetsAvailableCallback callback) {
308 if (api_key_.empty()) { 294 if (api_key_.empty()) {
309 // If we don't have an API key, don't even try. 295 // If we don't have an API key, don't even try.
310 FetchFinished(OptionalFetchedCategories(), std::move(callback), 296 FetchFinished(OptionalFetchedCategories(), std::move(callback),
311 FetchResult::MISSING_API_KEY, std::string()); 297 FetchResult::MISSING_API_KEY, std::string());
312 return; 298 return;
313 } 299 }
314 // When not providing OAuth token, we need to pass the Google API key. 300 // When not providing OAuth token, we need to pass the Google API key.
315 builder.SetUrl( 301 builder.SetUrl(
316 GURL(base::StringPrintf(kSnippetsServerNonAuthorizedFormat, 302 GURL(base::StringPrintf(kSnippetsServerNonAuthorizedFormat,
317 fetch_url_.spec().c_str(), api_key_.c_str()))); 303 fetch_url_.spec().c_str(), api_key_.c_str())));
318 StartRequest(std::move(builder), std::move(callback)); 304 StartRequest(std::move(builder), std::move(callback));
319 } 305 }
320 306
321 void RemoteSuggestionsFetcher::FetchSnippetsAuthenticated( 307 void RemoteSuggestionsFetcher::FetchSnippetsAuthenticated(
322 JsonRequest::Builder builder, 308 JsonRequest::Builder builder,
323 SnippetsAvailableCallback callback, 309 SnippetsAvailableCallback callback,
324 const std::string& account_id,
325 const std::string& oauth_access_token) { 310 const std::string& oauth_access_token) {
326 // TODO(jkrcal, treib): Add unit-tests for authenticated fetches. 311 // TODO(jkrcal, treib): Add unit-tests for authenticated fetches.
327 builder.SetUrl(fetch_url_) 312 builder.SetUrl(fetch_url_)
328 .SetAuthentication(account_id, 313 .SetAuthentication(signin_manager_->GetAuthenticatedAccountId(),
329 base::StringPrintf(kAuthorizationRequestHeaderFormat, 314 base::StringPrintf(kAuthorizationRequestHeaderFormat,
330 oauth_access_token.c_str())); 315 oauth_access_token.c_str()));
331 StartRequest(std::move(builder), std::move(callback)); 316 StartRequest(std::move(builder), std::move(callback));
332 } 317 }
333 318
334 void RemoteSuggestionsFetcher::StartRequest( 319 void RemoteSuggestionsFetcher::StartRequest(
335 JsonRequest::Builder builder, 320 JsonRequest::Builder builder,
336 SnippetsAvailableCallback callback) { 321 SnippetsAvailableCallback callback) {
337 std::unique_ptr<JsonRequest> request = builder.Build(); 322 std::unique_ptr<JsonRequest> request = builder.Build();
338 JsonRequest* raw_request = request.get(); 323 JsonRequest* raw_request = request.get();
339 raw_request->Start(base::BindOnce(&RemoteSuggestionsFetcher::JsonRequestDone, 324 raw_request->Start(base::BindOnce(&RemoteSuggestionsFetcher::JsonRequestDone,
340 base::Unretained(this), std::move(request), 325 base::Unretained(this), std::move(request),
341 std::move(callback))); 326 std::move(callback)));
342 } 327 }
343 328
344 void RemoteSuggestionsFetcher::StartTokenRequest() { 329 void RemoteSuggestionsFetcher::StartTokenRequest() {
345 OAuth2TokenService::ScopeSet scopes; 330 // If there is already an ongoing token request, just wait for that.
346 scopes.insert(kContentSuggestionsApiScope); 331 if (token_fetcher_) {
347 oauth_request_ = token_service_->StartRequest( 332 return;
348 signin_manager_->GetAuthenticatedAccountId(), scopes, this); 333 }
334
335 OAuth2TokenService::ScopeSet scopes{kContentSuggestionsApiScope};
336 token_fetcher_ = base::MakeUnique<AccessTokenFetcher>(
337 "ntp_snippets", signin_manager_, token_service_, scopes,
338 base::BindOnce(&RemoteSuggestionsFetcher::AccessTokenAvailable,
339 base::Unretained(this)));
349 } 340 }
350 341
351 //////////////////////////////////////////////////////////////////////////////// 342 void RemoteSuggestionsFetcher::AccessTokenAvailable(
jkrcal 2017/03/24 09:09:26 The naming is misleading for me as this function a
Marc Treib 2017/03/27 08:08:20 Done.
352 // OAuth2TokenService::Consumer overrides 343 const GoogleServiceAuthError& error,
353 void RemoteSuggestionsFetcher::OnGetTokenSuccess( 344 const std::string& access_token) {
354 const OAuth2TokenService::Request* request, 345 // Delete the fetcher after we leave this method.
jkrcal 2017/03/24 09:09:26 nit: I do not see the token_fetcher_ being used la
Marc Treib 2017/03/27 08:08:20 This method is called from the fetcher, so deletin
jkrcal 2017/03/27 08:35:59 Understood! nit: Can you expand the comment a bit
Marc Treib 2017/03/27 08:37:59 Sure, done!
355 const std::string& access_token, 346 DCHECK(token_fetcher_);
356 const base::Time& expiration_time) { 347 std::unique_ptr<AccessTokenFetcher> token_fetcher_deleter(
357 // Delete the request after we leave this method. 348 std::move(token_fetcher_));
358 std::unique_ptr<OAuth2TokenService::Request> oauth_request( 349
359 std::move(oauth_request_)); 350 if (error.state() != GoogleServiceAuthError::NONE) {
360 DCHECK_EQ(oauth_request.get(), request) 351 AccessTokenError(error);
361 << "Got tokens from some previous request"; 352 return;
353 }
354
355 DCHECK(!access_token.empty());
362 356
363 while (!pending_requests_.empty()) { 357 while (!pending_requests_.empty()) {
364 std::pair<JsonRequest::Builder, SnippetsAvailableCallback> 358 std::pair<JsonRequest::Builder, SnippetsAvailableCallback>
365 builder_and_callback = std::move(pending_requests_.front()); 359 builder_and_callback = std::move(pending_requests_.front());
366 pending_requests_.pop(); 360 pending_requests_.pop();
367 FetchSnippetsAuthenticated(std::move(builder_and_callback.first), 361 FetchSnippetsAuthenticated(std::move(builder_and_callback.first),
368 std::move(builder_and_callback.second), 362 std::move(builder_and_callback.second),
369 oauth_request->GetAccountId(), access_token); 363 access_token);
370 } 364 }
371 } 365 }
372 366
373 void RemoteSuggestionsFetcher::OnGetTokenFailure( 367 void RemoteSuggestionsFetcher::AccessTokenError(
374 const OAuth2TokenService::Request* request,
375 const GoogleServiceAuthError& error) { 368 const GoogleServiceAuthError& error) {
376 oauth_request_.reset(); 369 DCHECK_NE(error.state(), GoogleServiceAuthError::NONE);
377
378 if (!oauth_token_retried_ &&
379 error.state() == GoogleServiceAuthError::State::REQUEST_CANCELED) {
380 // The request (especially on startup) can get reset by loading the refresh
381 // token - do it one more time.
382 oauth_token_retried_ = true;
383 StartTokenRequest();
384 return;
385 }
386 370
387 DLOG(ERROR) << "Unable to get token: " << error.ToString(); 371 DLOG(ERROR) << "Unable to get token: " << error.ToString();
372
388 while (!pending_requests_.empty()) { 373 while (!pending_requests_.empty()) {
389 std::pair<JsonRequest::Builder, SnippetsAvailableCallback> 374 std::pair<JsonRequest::Builder, SnippetsAvailableCallback>
390 builder_and_callback = std::move(pending_requests_.front()); 375 builder_and_callback = std::move(pending_requests_.front());
391 376
392 FetchFinished(OptionalFetchedCategories(), 377 FetchFinished(OptionalFetchedCategories(),
393 std::move(builder_and_callback.second), 378 std::move(builder_and_callback.second),
394 FetchResult::OAUTH_TOKEN_ERROR, 379 FetchResult::OAUTH_TOKEN_ERROR,
395 /*error_details=*/base::StringPrintf( 380 /*error_details=*/base::StringPrintf(
396 " (%s)", error.ToString().c_str())); 381 " (%s)", error.ToString().c_str()));
397 pending_requests_.pop(); 382 pending_requests_.pop();
398 } 383 }
399 } 384 }
400 385
401 ////////////////////////////////////////////////////////////////////////////////
402 // OAuth2TokenService::Observer overrides
403 void RemoteSuggestionsFetcher::OnRefreshTokenAvailable(
404 const std::string& account_id) {
405 // Only react on tokens for the account the user has signed in with.
406 if (account_id != signin_manager_->GetAuthenticatedAccountId()) {
407 return;
408 }
409
410 token_service_->RemoveObserver(this);
411 waiting_for_refresh_token_ = false;
412 oauth_token_retried_ = false;
413 StartTokenRequest();
414 }
415
416 void RemoteSuggestionsFetcher::JsonRequestDone( 386 void RemoteSuggestionsFetcher::JsonRequestDone(
417 std::unique_ptr<JsonRequest> request, 387 std::unique_ptr<JsonRequest> request,
418 SnippetsAvailableCallback callback, 388 SnippetsAvailableCallback callback,
419 std::unique_ptr<base::Value> result, 389 std::unique_ptr<base::Value> result,
420 FetchResult status_code, 390 FetchResult status_code,
421 const std::string& error_details) { 391 const std::string& error_details) {
422 DCHECK(request); 392 DCHECK(request);
423 // Record the time when request for fetching remote content snippets finished. 393 // Record the time when request for fetching remote content snippets finished.
424 const base::Time fetch_time = clock_->Now(); 394 const base::Time fetch_time = clock_->Now();
425 395
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after
519 category, BuildRemoteCategoryInfo(base::UTF8ToUTF16(utf8_title), 489 category, BuildRemoteCategoryInfo(base::UTF8ToUTF16(utf8_title),
520 allow_fetching_more_results))); 490 allow_fetching_more_results)));
521 } 491 }
522 categories->back().suggestions = std::move(suggestions); 492 categories->back().suggestions = std::move(suggestions);
523 } 493 }
524 494
525 return true; 495 return true;
526 } 496 }
527 497
528 } // namespace ntp_snippets 498 } // namespace ntp_snippets
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698