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" |
| (...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 99 return endpoint.empty() ? kChromeReaderServer : endpoint; | 99 return endpoint.empty() ? kChromeReaderServer : endpoint; |
| 100 } | 100 } |
| 101 | 101 |
| 102 bool UsesChromeContentSuggestionsAPI(const GURL& endpoint) { | 102 bool UsesChromeContentSuggestionsAPI(const GURL& endpoint) { |
| 103 if (endpoint == GURL(kChromeReaderServer)) { | 103 if (endpoint == GURL(kChromeReaderServer)) { |
| 104 return false; | 104 return false; |
| 105 } else if (endpoint != GURL(kContentSuggestionsServer) && | 105 } else if (endpoint != GURL(kContentSuggestionsServer) && |
| 106 endpoint != GURL(kContentSuggestionsDevServer) && | 106 endpoint != GURL(kContentSuggestionsDevServer) && |
| 107 endpoint != GURL(kContentSuggestionsAlphaServer)) { | 107 endpoint != GURL(kContentSuggestionsAlphaServer)) { |
| 108 LOG(WARNING) << "Unknown value for " << kContentSuggestionsBackend << ": " | 108 LOG(WARNING) << "Unknown value for " << kContentSuggestionsBackend << ": " |
| 109 << "assuming chromecontentsuggestions-style API"; | 109 << "assuming chromecontentsuggestions-style API"; |
| 110 } | 110 } |
| 111 return true; | 111 return true; |
| 112 } | 112 } |
| 113 | 113 |
| 114 // Creates snippets from dictionary values in |list| and adds them to | 114 // Creates snippets from dictionary values in |list| and adds them to |
| 115 // |snippets|. Returns true on success, false if anything went wrong. | 115 // |snippets|. Returns true on success, false if anything went wrong. |
| 116 bool AddSnippetsFromListValue(bool content_suggestions_api, | 116 bool AddSnippetsFromListValue(bool content_suggestions_api, |
| 117 const base::ListValue& list, | 117 const base::ListValue& list, |
| 118 NTPSnippet::PtrVector* snippets) { | 118 NTPSnippet::PtrVector* snippets) { |
| 119 for (const auto& value : list) { | 119 for (const auto& value : list) { |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 162 token_service_(token_service), | 162 token_service_(token_service), |
| 163 waiting_for_refresh_token_(false), | 163 waiting_for_refresh_token_(false), |
| 164 url_request_context_getter_(url_request_context_getter), | 164 url_request_context_getter_(url_request_context_getter), |
| 165 category_factory_(category_factory), | 165 category_factory_(category_factory), |
| 166 parse_json_callback_(parse_json_callback), | 166 parse_json_callback_(parse_json_callback), |
| 167 fetch_url_(GetFetchEndpoint()), | 167 fetch_url_(GetFetchEndpoint()), |
| 168 fetch_api_(UsesChromeContentSuggestionsAPI(fetch_url_) | 168 fetch_api_(UsesChromeContentSuggestionsAPI(fetch_url_) |
| 169 ? CHROME_CONTENT_SUGGESTIONS_API | 169 ? CHROME_CONTENT_SUGGESTIONS_API |
| 170 : CHROME_READER_API), | 170 : CHROME_READER_API), |
| 171 is_stable_channel_(is_stable_channel), | 171 is_stable_channel_(is_stable_channel), |
| 172 interactive_request_(false), | |
| 172 tick_clock_(new base::DefaultTickClock()), | 173 tick_clock_(new base::DefaultTickClock()), |
| 173 request_throttler_( | 174 request_throttler_( |
| 174 pref_service, | 175 pref_service, |
| 175 RequestThrottler::RequestType::CONTENT_SUGGESTION_FETCHER), | 176 RequestThrottler::RequestType::CONTENT_SUGGESTION_FETCHER), |
| 176 oauth_token_retried_(false), | 177 oauth_token_retried_(false), |
| 177 weak_ptr_factory_(this) { | 178 weak_ptr_factory_(this) { |
| 178 // Parse the variation parameters and set the defaults if missing. | 179 // Parse the variation parameters and set the defaults if missing. |
| 179 std::string personalization = variations::GetVariationParamValue( | 180 std::string personalization = variations::GetVariationParamValue( |
| 180 ntp_snippets::kStudyName, kPersonalizationName); | 181 ntp_snippets::kStudyName, kPersonalizationName); |
| 181 if (personalization == kPersonalizationNonPersonalString) { | 182 if (personalization == kPersonalizationNonPersonalString) { |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 227 if (UsesHostRestrictions() && hosts_.empty()) { | 228 if (UsesHostRestrictions() && hosts_.empty()) { |
| 228 FetchFinished(OptionalSnippets(), FetchResult::EMPTY_HOSTS, | 229 FetchFinished(OptionalSnippets(), FetchResult::EMPTY_HOSTS, |
| 229 /*extra_message=*/std::string()); | 230 /*extra_message=*/std::string()); |
| 230 return; | 231 return; |
| 231 } | 232 } |
| 232 | 233 |
| 233 locale_ = PosixLocaleFromBCP47Language(language_code); | 234 locale_ = PosixLocaleFromBCP47Language(language_code); |
| 234 count_to_fetch_ = count; | 235 count_to_fetch_ = count; |
| 235 | 236 |
| 236 bool use_authentication = UsesAuthentication(); | 237 bool use_authentication = UsesAuthentication(); |
| 238 interactive_request_ = interactive_request; | |
| 237 | 239 |
| 238 if (use_authentication && signin_manager_->IsAuthenticated()) { | 240 if (use_authentication && signin_manager_->IsAuthenticated()) { |
| 239 // Signed-in: get OAuth token --> fetch snippets. | 241 // Signed-in: get OAuth token --> fetch snippets. |
| 240 oauth_token_retried_ = false; | 242 oauth_token_retried_ = false; |
| 241 StartTokenRequest(); | 243 StartTokenRequest(); |
| 242 } else if (use_authentication && signin_manager_->AuthInProgress()) { | 244 } else if (use_authentication && signin_manager_->AuthInProgress()) { |
| 243 // Currently signing in: wait for auth to finish (the refresh token) --> | 245 // Currently signing in: wait for auth to finish (the refresh token) --> |
| 244 // get OAuth token --> fetch snippets. | 246 // get OAuth token --> fetch snippets. |
| 245 if (!waiting_for_refresh_token_) { | 247 if (!waiting_for_refresh_token_) { |
| 246 // Wait until we get a refresh token. | 248 // Wait until we get a refresh token. |
| 247 waiting_for_refresh_token_ = true; | 249 waiting_for_refresh_token_ = true; |
| 248 token_service_->AddObserver(this); | 250 token_service_->AddObserver(this); |
| 249 } | 251 } |
| 250 } else { | 252 } else { |
| 251 // Not signed in: fetch snippets (without authentication). | 253 // Not signed in: fetch snippets (without authentication). |
| 252 FetchSnippetsNonAuthenticated(); | 254 FetchSnippetsNonAuthenticated(); |
| 253 } | 255 } |
| 254 } | 256 } |
| 255 | 257 |
| 256 NTPSnippetsFetcher::RequestParams::RequestParams() | 258 NTPSnippetsFetcher::RequestParams::RequestParams() |
| 257 : fetch_api(), | 259 : fetch_api(), |
| 258 obfuscated_gaia_id(), | 260 obfuscated_gaia_id(), |
| 259 only_return_personalized_results(), | 261 only_return_personalized_results(), |
| 260 user_locale(), | 262 user_locale(), |
| 261 host_restricts(), | 263 host_restricts(), |
| 262 count_to_fetch() {} | 264 count_to_fetch() {} |
|
Marc Treib
2016/08/25 09:26:58
Also initialize interactive_request here
vitaliii
2016/08/26 09:13:46
Done.
| |
| 263 | 265 |
| 264 NTPSnippetsFetcher::RequestParams::~RequestParams() = default; | 266 NTPSnippetsFetcher::RequestParams::~RequestParams() = default; |
| 265 | 267 |
| 266 std::string NTPSnippetsFetcher::RequestParams::BuildRequest() { | 268 std::string NTPSnippetsFetcher::RequestParams::BuildRequest() { |
| 267 auto request = base::MakeUnique<base::DictionaryValue>(); | 269 auto request = base::MakeUnique<base::DictionaryValue>(); |
| 268 switch (fetch_api) { | 270 switch (fetch_api) { |
| 269 case CHROME_READER_API: { | 271 case CHROME_READER_API: { |
| 270 auto content_params = base::MakeUnique<base::DictionaryValue>(); | 272 auto content_params = base::MakeUnique<base::DictionaryValue>(); |
| 271 content_params->SetBoolean("only_return_personalized_results", | 273 content_params->SetBoolean("only_return_personalized_results", |
| 272 only_return_personalized_results); | 274 only_return_personalized_results); |
| (...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 315 | 317 |
| 316 case CHROME_CONTENT_SUGGESTIONS_API: { | 318 case CHROME_CONTENT_SUGGESTIONS_API: { |
| 317 if (!user_locale.empty()) { | 319 if (!user_locale.empty()) { |
| 318 request->SetString("uiLanguage", user_locale); | 320 request->SetString("uiLanguage", user_locale); |
| 319 } | 321 } |
| 320 auto regular_hosts = base::MakeUnique<base::ListValue>(); | 322 auto regular_hosts = base::MakeUnique<base::ListValue>(); |
| 321 for (const auto& host : host_restricts) { | 323 for (const auto& host : host_restricts) { |
| 322 regular_hosts->AppendString(host); | 324 regular_hosts->AppendString(host); |
| 323 } | 325 } |
| 324 request->Set("regularlyVisitedHostNames", std::move(regular_hosts)); | 326 request->Set("regularlyVisitedHostNames", std::move(regular_hosts)); |
| 327 request->SetString("type", | |
| 328 interactive_request ? "INTERACTIVE" : "BACKGROUND"); | |
| 325 | 329 |
| 326 // TODO(sfiera): support authentication and personalization | 330 // TODO(sfiera): support authentication and personalization |
| 327 // TODO(sfiera): support count_to_fetch | 331 // TODO(sfiera): support count_to_fetch |
| 328 break; | 332 break; |
| 329 } | 333 } |
| 330 } | 334 } |
| 331 | 335 |
| 332 std::string request_json; | 336 std::string request_json; |
| 333 bool success = base::JSONWriter::WriteWithOptions( | 337 bool success = base::JSONWriter::WriteWithOptions( |
| 334 *request, base::JSONWriter::OPTIONS_PRETTY_PRINT, &request_json); | 338 *request, base::JSONWriter::OPTIONS_PRETTY_PRINT, &request_json); |
| (...skipping 19 matching lines...) Expand all Loading... | |
| 354 headers.SetHeader("Content-Type", "application/json; charset=UTF-8"); | 358 headers.SetHeader("Content-Type", "application/json; charset=UTF-8"); |
| 355 // Add X-Client-Data header with experiment IDs from field trials. | 359 // Add X-Client-Data header with experiment IDs from field trials. |
| 356 variations::AppendVariationHeaders(url, | 360 variations::AppendVariationHeaders(url, |
| 357 false, // incognito | 361 false, // incognito |
| 358 false, // uma_enabled | 362 false, // uma_enabled |
| 359 &headers); | 363 &headers); |
| 360 url_fetcher_->SetExtraRequestHeaders(headers.ToString()); | 364 url_fetcher_->SetExtraRequestHeaders(headers.ToString()); |
| 361 url_fetcher_->SetUploadData("application/json", request); | 365 url_fetcher_->SetUploadData("application/json", request); |
| 362 // Log the request for debugging network issues. | 366 // Log the request for debugging network issues. |
| 363 VLOG(1) << "Sending a NTP snippets request to " << url << ":" << std::endl | 367 VLOG(1) << "Sending a NTP snippets request to " << url << ":" << std::endl |
| 364 << headers.ToString() << std::endl << request; | 368 << headers.ToString() << std::endl |
| 369 << request; | |
| 365 // Fetchers are sometimes cancelled because a network change was detected. | 370 // Fetchers are sometimes cancelled because a network change was detected. |
| 366 url_fetcher_->SetAutomaticallyRetryOnNetworkChanges(3); | 371 url_fetcher_->SetAutomaticallyRetryOnNetworkChanges(3); |
| 367 // Try to make fetching the files bit more robust even with poor connection. | 372 // Try to make fetching the files bit more robust even with poor connection. |
| 368 url_fetcher_->SetMaxRetriesOn5xx(3); | 373 url_fetcher_->SetMaxRetriesOn5xx(3); |
| 369 url_fetcher_->Start(); | 374 url_fetcher_->Start(); |
| 370 } | 375 } |
| 371 | 376 |
| 372 bool NTPSnippetsFetcher::UsesHostRestrictions() const { | 377 bool NTPSnippetsFetcher::UsesHostRestrictions() const { |
| 373 return use_host_restriction_ && | 378 return use_host_restriction_ && |
| 374 !base::CommandLine::ForCurrentProcess()->HasSwitch( | 379 !base::CommandLine::ForCurrentProcess()->HasSwitch( |
| (...skipping 11 matching lines...) Expand all Loading... | |
| 386 ? google_apis::GetAPIKey() | 391 ? google_apis::GetAPIKey() |
| 387 : google_apis::GetNonStableAPIKey(); | 392 : google_apis::GetNonStableAPIKey(); |
| 388 GURL url(base::StringPrintf(kSnippetsServerNonAuthorizedFormat, | 393 GURL url(base::StringPrintf(kSnippetsServerNonAuthorizedFormat, |
| 389 fetch_url_.spec().c_str(), key.c_str())); | 394 fetch_url_.spec().c_str(), key.c_str())); |
| 390 | 395 |
| 391 RequestParams params; | 396 RequestParams params; |
| 392 params.fetch_api = fetch_api_; | 397 params.fetch_api = fetch_api_; |
| 393 params.host_restricts = | 398 params.host_restricts = |
| 394 UsesHostRestrictions() ? hosts_ : std::set<std::string>(); | 399 UsesHostRestrictions() ? hosts_ : std::set<std::string>(); |
| 395 params.count_to_fetch = count_to_fetch_; | 400 params.count_to_fetch = count_to_fetch_; |
| 401 params.interactive_request = interactive_request_; | |
| 396 FetchSnippetsImpl(url, std::string(), params.BuildRequest()); | 402 FetchSnippetsImpl(url, std::string(), params.BuildRequest()); |
| 397 } | 403 } |
| 398 | 404 |
| 399 void NTPSnippetsFetcher::FetchSnippetsAuthenticated( | 405 void NTPSnippetsFetcher::FetchSnippetsAuthenticated( |
| 400 const std::string& account_id, | 406 const std::string& account_id, |
| 401 const std::string& oauth_access_token) { | 407 const std::string& oauth_access_token) { |
| 402 RequestParams params; | 408 RequestParams params; |
| 403 params.fetch_api = fetch_api_; | 409 params.fetch_api = fetch_api_; |
| 404 params.obfuscated_gaia_id = account_id; | 410 params.obfuscated_gaia_id = account_id; |
| 405 params.only_return_personalized_results = | 411 params.only_return_personalized_results = |
| 406 personalization_ == Personalization::kPersonal; | 412 personalization_ == Personalization::kPersonal; |
| 407 params.user_locale = locale_; | 413 params.user_locale = locale_; |
| 408 params.host_restricts = | 414 params.host_restricts = |
| 409 UsesHostRestrictions() ? hosts_ : std::set<std::string>(); | 415 UsesHostRestrictions() ? hosts_ : std::set<std::string>(); |
| 410 params.count_to_fetch = count_to_fetch_; | 416 params.count_to_fetch = count_to_fetch_; |
| 417 params.interactive_request = interactive_request_; | |
| 411 // TODO(jkrcal, treib): Add unit-tests for authenticated fetches. | 418 // TODO(jkrcal, treib): Add unit-tests for authenticated fetches. |
| 412 FetchSnippetsImpl(fetch_url_, | 419 FetchSnippetsImpl(fetch_url_, |
| 413 base::StringPrintf(kAuthorizationRequestHeaderFormat, | 420 base::StringPrintf(kAuthorizationRequestHeaderFormat, |
| 414 oauth_access_token.c_str()), | 421 oauth_access_token.c_str()), |
| 415 params.BuildRequest()); | 422 params.BuildRequest()); |
| 416 } | 423 } |
| 417 | 424 |
| 418 void NTPSnippetsFetcher::StartTokenRequest() { | 425 void NTPSnippetsFetcher::StartTokenRequest() { |
| 419 OAuth2TokenService::ScopeSet scopes; | 426 OAuth2TokenService::ScopeSet scopes; |
| 420 scopes.insert(fetch_api_ == CHROME_CONTENT_SUGGESTIONS_API | 427 scopes.insert(fetch_api_ == CHROME_CONTENT_SUGGESTIONS_API |
| (...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 490 } else if (source->GetResponseCode() != net::HTTP_OK) { | 497 } else if (source->GetResponseCode() != net::HTTP_OK) { |
| 491 // TODO(jkrcal): https://crbug.com/609084 | 498 // TODO(jkrcal): https://crbug.com/609084 |
| 492 // We need to deal with the edge case again where the auth | 499 // We need to deal with the edge case again where the auth |
| 493 // token expires just before we send the request (in which case we need to | 500 // token expires just before we send the request (in which case we need to |
| 494 // fetch a new auth token). We should extract that into a common class | 501 // fetch a new auth token). We should extract that into a common class |
| 495 // instead of adding it to every single class that uses auth tokens. | 502 // instead of adding it to every single class that uses auth tokens. |
| 496 FetchFinished( | 503 FetchFinished( |
| 497 OptionalSnippets(), FetchResult::HTTP_ERROR, | 504 OptionalSnippets(), FetchResult::HTTP_ERROR, |
| 498 /*extra_message=*/base::StringPrintf(" %d", source->GetResponseCode())); | 505 /*extra_message=*/base::StringPrintf(" %d", source->GetResponseCode())); |
| 499 } else { | 506 } else { |
| 500 bool stores_result_to_string = source->GetResponseAsString( | 507 bool stores_result_to_string = |
| 501 &last_fetch_json_); | 508 source->GetResponseAsString(&last_fetch_json_); |
| 502 DCHECK(stores_result_to_string); | 509 DCHECK(stores_result_to_string); |
| 503 | 510 |
| 504 parse_json_callback_.Run( | 511 parse_json_callback_.Run(last_fetch_json_, |
| 505 last_fetch_json_, | 512 base::Bind(&NTPSnippetsFetcher::OnJsonParsed, |
| 506 base::Bind(&NTPSnippetsFetcher::OnJsonParsed, | 513 weak_ptr_factory_.GetWeakPtr()), |
| 507 weak_ptr_factory_.GetWeakPtr()), | 514 base::Bind(&NTPSnippetsFetcher::OnJsonError, |
| 508 base::Bind(&NTPSnippetsFetcher::OnJsonError, | 515 weak_ptr_factory_.GetWeakPtr())); |
| 509 weak_ptr_factory_.GetWeakPtr())); | |
| 510 } | 516 } |
| 511 } | 517 } |
| 512 | 518 |
| 513 bool NTPSnippetsFetcher::JsonToSnippets(const base::Value& parsed, | 519 bool NTPSnippetsFetcher::JsonToSnippets(const base::Value& parsed, |
| 514 NTPSnippet::CategoryMap* snippets) { | 520 NTPSnippet::CategoryMap* snippets) { |
| 515 const base::DictionaryValue* top_dict = nullptr; | 521 const base::DictionaryValue* top_dict = nullptr; |
| 516 if (!parsed.GetAsDictionary(&top_dict)) { | 522 if (!parsed.GetAsDictionary(&top_dict)) { |
| 517 return false; | 523 return false; |
| 518 } | 524 } |
| 519 | 525 |
| (...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 565 /*extra_message=*/std::string()); | 571 /*extra_message=*/std::string()); |
| 566 } else { | 572 } else { |
| 567 LOG(WARNING) << "Received invalid snippets: " << last_fetch_json_; | 573 LOG(WARNING) << "Received invalid snippets: " << last_fetch_json_; |
| 568 FetchFinished(OptionalSnippets(), | 574 FetchFinished(OptionalSnippets(), |
| 569 FetchResult::INVALID_SNIPPET_CONTENT_ERROR, | 575 FetchResult::INVALID_SNIPPET_CONTENT_ERROR, |
| 570 /*extra_message=*/std::string()); | 576 /*extra_message=*/std::string()); |
| 571 } | 577 } |
| 572 } | 578 } |
| 573 | 579 |
| 574 void NTPSnippetsFetcher::OnJsonError(const std::string& error) { | 580 void NTPSnippetsFetcher::OnJsonError(const std::string& error) { |
| 575 LOG(WARNING) << "Received invalid JSON (" << error << "): " | 581 LOG(WARNING) << "Received invalid JSON (" << error |
| 576 << last_fetch_json_; | 582 << "): " << last_fetch_json_; |
|
Marc Treib
2016/08/25 09:26:58
Was this auto-formatted?! (It's fine either way, I
vitaliii
2016/08/26 09:13:46
Yes.
Eclipse format happened to differ from git c
| |
| 577 FetchFinished( | 583 FetchFinished( |
| 578 OptionalSnippets(), FetchResult::JSON_PARSE_ERROR, | 584 OptionalSnippets(), FetchResult::JSON_PARSE_ERROR, |
| 579 /*extra_message=*/base::StringPrintf(" (error %s)", error.c_str())); | 585 /*extra_message=*/base::StringPrintf(" (error %s)", error.c_str())); |
| 580 } | 586 } |
| 581 | 587 |
| 582 void NTPSnippetsFetcher::FetchFinished(OptionalSnippets snippets, | 588 void NTPSnippetsFetcher::FetchFinished(OptionalSnippets snippets, |
| 583 FetchResult result, | 589 FetchResult result, |
| 584 const std::string& extra_message) { | 590 const std::string& extra_message) { |
| 585 DCHECK(result == FetchResult::SUCCESS || !snippets); | 591 DCHECK(result == FetchResult::SUCCESS || !snippets); |
| 586 last_status_ = FetchResultToString(result) + extra_message; | 592 last_status_ = FetchResultToString(result) + extra_message; |
| 587 | 593 |
| 588 // If the result is EMPTY_HOSTS or OAUTH_TOKEN_ERROR, we didn't actually send | 594 // If the result is EMPTY_HOSTS or OAUTH_TOKEN_ERROR, we didn't actually send |
| 589 // a network request, so don't record FetchTime in those cases. | 595 // a network request, so don't record FetchTime in those cases. |
| 590 if (result != FetchResult::EMPTY_HOSTS && | 596 if (result != FetchResult::EMPTY_HOSTS && |
| 591 result != FetchResult::OAUTH_TOKEN_ERROR) { | 597 result != FetchResult::OAUTH_TOKEN_ERROR) { |
| 592 UMA_HISTOGRAM_TIMES("NewTabPage.Snippets.FetchTime", | 598 UMA_HISTOGRAM_TIMES("NewTabPage.Snippets.FetchTime", |
| 593 tick_clock_->NowTicks() - fetch_start_time_); | 599 tick_clock_->NowTicks() - fetch_start_time_); |
| 594 } | 600 } |
| 595 UMA_HISTOGRAM_ENUMERATION("NewTabPage.Snippets.FetchResult", | 601 UMA_HISTOGRAM_ENUMERATION("NewTabPage.Snippets.FetchResult", |
| 596 static_cast<int>(result), | 602 static_cast<int>(result), |
| 597 static_cast<int>(FetchResult::RESULT_MAX)); | 603 static_cast<int>(FetchResult::RESULT_MAX)); |
| 598 | 604 |
| 599 if (!snippets_available_callback_.is_null()) | 605 if (!snippets_available_callback_.is_null()) |
| 600 snippets_available_callback_.Run(std::move(snippets)); | 606 snippets_available_callback_.Run(std::move(snippets)); |
| 601 } | 607 } |
| 602 | 608 |
| 603 } // namespace ntp_snippets | 609 } // namespace ntp_snippets |
| OLD | NEW |