OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 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/suggestions/suggestions_service.h" | 5 #include "components/suggestions/suggestions_service_impl.h" |
6 | 6 |
7 #include <memory> | 7 #include <memory> |
8 #include <utility> | 8 #include <utility> |
9 | 9 |
10 #include "base/feature_list.h" | 10 #include "base/feature_list.h" |
11 #include "base/location.h" | 11 #include "base/location.h" |
12 #include "base/metrics/histogram_macros.h" | 12 #include "base/metrics/histogram_macros.h" |
13 #include "base/metrics/sparse_histogram.h" | 13 #include "base/metrics/sparse_histogram.h" |
14 #include "base/strings/string_number_conversions.h" | 14 #include "base/strings/string_number_conversions.h" |
15 #include "base/strings/string_util.h" | 15 #include "base/strings/string_util.h" |
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
104 GURL GetGoogleBaseURL() { | 104 GURL GetGoogleBaseURL() { |
105 GURL url(google_util::CommandLineGoogleBaseURL()); | 105 GURL url(google_util::CommandLineGoogleBaseURL()); |
106 if (url.is_valid()) | 106 if (url.is_valid()) |
107 return url; | 107 return url; |
108 return GURL(kDefaultGoogleBaseURL); | 108 return GURL(kDefaultGoogleBaseURL); |
109 } | 109 } |
110 | 110 |
111 // Format strings for the various suggestions URLs. They all have two string | 111 // Format strings for the various suggestions URLs. They all have two string |
112 // params: The Google base URL and the device type. | 112 // params: The Google base URL and the device type. |
113 // TODO(mathp): Put this in TemplateURL. | 113 // TODO(mathp): Put this in TemplateURL. |
114 const char kSuggestionsURLFormat[] = | 114 const char kSuggestionsURLFormat[] = "%schromesuggestions?t=%s"; |
115 "%schromesuggestions?t=%s"; | |
116 const char kSuggestionsBlacklistURLPrefixFormat[] = | 115 const char kSuggestionsBlacklistURLPrefixFormat[] = |
117 "%schromesuggestions/blacklist?t=%s&url="; | 116 "%schromesuggestions/blacklist?t=%s&url="; |
118 const char kSuggestionsBlacklistClearURLFormat[] = | 117 const char kSuggestionsBlacklistClearURLFormat[] = |
119 "%schromesuggestions/blacklist/clear?t=%s"; | 118 "%schromesuggestions/blacklist/clear?t=%s"; |
120 | 119 |
121 const char kSuggestionsBlacklistURLParam[] = "url"; | 120 const char kSuggestionsBlacklistURLParam[] = "url"; |
122 | 121 |
123 #if defined(OS_ANDROID) || defined(OS_IOS) | 122 #if defined(OS_ANDROID) || defined(OS_IOS) |
124 const char kDeviceType[] = "2"; | 123 const char kDeviceType[] = "2"; |
125 #else | 124 #else |
126 const char kDeviceType[] = "1"; | 125 const char kDeviceType[] = "1"; |
127 #endif | 126 #endif |
128 | 127 |
129 // Format string for OAuth2 authentication headers. | 128 // Format string for OAuth2 authentication headers. |
130 const char kAuthorizationHeaderFormat[] = "Authorization: Bearer %s"; | 129 const char kAuthorizationHeaderFormat[] = "Authorization: Bearer %s"; |
131 | 130 |
132 const char kFaviconURL[] = | 131 const char kFaviconURL[] = |
133 "https://s2.googleusercontent.com/s2/favicons?domain_url=%s&alt=s&sz=32"; | 132 "https://s2.googleusercontent.com/s2/favicons?domain_url=%s&alt=s&sz=32"; |
134 | 133 |
135 // The default expiry timeout is 168 hours. | 134 // The default expiry timeout is 168 hours. |
136 const int64_t kDefaultExpiryUsec = 168 * base::Time::kMicrosecondsPerHour; | 135 const int64_t kDefaultExpiryUsec = 168 * base::Time::kMicrosecondsPerHour; |
137 | 136 |
138 } // namespace | 137 } // namespace |
139 | 138 |
140 // Helper class for fetching OAuth2 access tokens. | 139 // Helper class for fetching OAuth2 access tokens. |
141 // To get a token, call |GetAccessToken|. Does not support multiple concurrent | 140 // To get a token, call |GetAccessToken|. Does not support multiple concurrent |
142 // token requests, i.e. check |HasPendingRequest| first. | 141 // token requests, i.e. check |HasPendingRequest| first. |
143 class SuggestionsService::AccessTokenFetcher | 142 class SuggestionsServiceImpl::AccessTokenFetcher |
144 : public OAuth2TokenService::Consumer { | 143 : public OAuth2TokenService::Consumer { |
145 public: | 144 public: |
146 using TokenCallback = base::Callback<void(const std::string&)>; | 145 using TokenCallback = base::Callback<void(const std::string&)>; |
147 | 146 |
148 AccessTokenFetcher(const SigninManagerBase* signin_manager, | 147 AccessTokenFetcher(const SigninManagerBase* signin_manager, |
149 OAuth2TokenService* token_service) | 148 OAuth2TokenService* token_service) |
150 : OAuth2TokenService::Consumer("suggestions_service"), | 149 : OAuth2TokenService::Consumer("suggestions_service"), |
151 signin_manager_(signin_manager), | 150 signin_manager_(signin_manager), |
152 token_service_(token_service) {} | 151 token_service_(token_service) {} |
153 | 152 |
154 void GetAccessToken(const TokenCallback& callback) { | 153 void GetAccessToken(const TokenCallback& callback) { |
155 callback_ = callback; | 154 callback_ = callback; |
156 std::string account_id; | 155 std::string account_id; |
157 // |signin_manager_| can be null in unit tests. | 156 // |signin_manager_| can be null in unit tests. |
158 if (signin_manager_) | 157 if (signin_manager_) |
159 account_id = signin_manager_->GetAuthenticatedAccountId(); | 158 account_id = signin_manager_->GetAuthenticatedAccountId(); |
160 OAuth2TokenService::ScopeSet scopes; | 159 OAuth2TokenService::ScopeSet scopes; |
161 scopes.insert(GaiaConstants::kChromeSyncOAuth2Scope); | 160 scopes.insert(GaiaConstants::kChromeSyncOAuth2Scope); |
162 token_request_ = token_service_->StartRequest(account_id, scopes, this); | 161 token_request_ = token_service_->StartRequest(account_id, scopes, this); |
163 } | 162 } |
164 | 163 |
165 bool HasPendingRequest() const { | 164 bool HasPendingRequest() const { return !!token_request_.get(); } |
166 return !!token_request_.get(); | |
167 } | |
168 | 165 |
169 private: | 166 private: |
170 void OnGetTokenSuccess(const OAuth2TokenService::Request* request, | 167 void OnGetTokenSuccess(const OAuth2TokenService::Request* request, |
171 const std::string& access_token, | 168 const std::string& access_token, |
172 const base::Time& expiration_time) override { | 169 const base::Time& expiration_time) override { |
173 DCHECK_EQ(request, token_request_.get()); | 170 DCHECK_EQ(request, token_request_.get()); |
174 callback_.Run(access_token); | 171 callback_.Run(access_token); |
175 token_request_.reset(nullptr); | 172 token_request_.reset(nullptr); |
176 } | 173 } |
177 | 174 |
178 void OnGetTokenFailure(const OAuth2TokenService::Request* request, | 175 void OnGetTokenFailure(const OAuth2TokenService::Request* request, |
179 const GoogleServiceAuthError& error) override { | 176 const GoogleServiceAuthError& error) override { |
180 DCHECK_EQ(request, token_request_.get()); | 177 DCHECK_EQ(request, token_request_.get()); |
181 LOG(WARNING) << "Token error: " << error.ToString(); | 178 LOG(WARNING) << "Token error: " << error.ToString(); |
182 callback_.Run(std::string()); | 179 callback_.Run(std::string()); |
183 token_request_.reset(nullptr); | 180 token_request_.reset(nullptr); |
184 } | 181 } |
185 | 182 |
186 const SigninManagerBase* signin_manager_; | 183 const SigninManagerBase* signin_manager_; |
187 OAuth2TokenService* token_service_; | 184 OAuth2TokenService* token_service_; |
188 | 185 |
189 TokenCallback callback_; | 186 TokenCallback callback_; |
190 std::unique_ptr<OAuth2TokenService::Request> token_request_; | 187 std::unique_ptr<OAuth2TokenService::Request> token_request_; |
191 }; | 188 }; |
192 | 189 |
193 SuggestionsService::SuggestionsService( | 190 SuggestionsServiceImpl::SuggestionsServiceImpl( |
194 const SigninManagerBase* signin_manager, | 191 const SigninManagerBase* signin_manager, |
195 OAuth2TokenService* token_service, | 192 OAuth2TokenService* token_service, |
196 syncer::SyncService* sync_service, | 193 syncer::SyncService* sync_service, |
197 net::URLRequestContextGetter* url_request_context, | 194 net::URLRequestContextGetter* url_request_context, |
198 std::unique_ptr<SuggestionsStore> suggestions_store, | 195 std::unique_ptr<SuggestionsStore> suggestions_store, |
199 std::unique_ptr<ImageManager> thumbnail_manager, | 196 std::unique_ptr<ImageManager> thumbnail_manager, |
200 std::unique_ptr<BlacklistStore> blacklist_store) | 197 std::unique_ptr<BlacklistStore> blacklist_store) |
201 : sync_service_(sync_service), | 198 : sync_service_(sync_service), |
202 sync_service_observer_(this), | 199 sync_service_observer_(this), |
203 url_request_context_(url_request_context), | 200 url_request_context_(url_request_context), |
204 suggestions_store_(std::move(suggestions_store)), | 201 suggestions_store_(std::move(suggestions_store)), |
205 thumbnail_manager_(std::move(thumbnail_manager)), | 202 thumbnail_manager_(std::move(thumbnail_manager)), |
206 blacklist_store_(std::move(blacklist_store)), | 203 blacklist_store_(std::move(blacklist_store)), |
207 scheduling_delay_(TimeDelta::FromSeconds(kDefaultSchedulingDelaySec)), | 204 scheduling_delay_(TimeDelta::FromSeconds(kDefaultSchedulingDelaySec)), |
208 token_fetcher_(new AccessTokenFetcher(signin_manager, token_service)), | 205 token_fetcher_(new AccessTokenFetcher(signin_manager, token_service)), |
209 weak_ptr_factory_(this) { | 206 weak_ptr_factory_(this) { |
210 // |sync_service_| is null if switches::kDisableSync is set (tests use that). | 207 // |sync_service_| is null if switches::kDisableSync is set (tests use that). |
211 if (sync_service_) | 208 if (sync_service_) |
212 sync_service_observer_.Add(sync_service_); | 209 sync_service_observer_.Add(sync_service_); |
213 // Immediately get the current sync state, so we'll flush the cache if | 210 // Immediately get the current sync state, so we'll flush the cache if |
214 // necessary. | 211 // necessary. |
215 OnStateChanged(); | 212 OnStateChanged(); |
216 } | 213 } |
217 | 214 |
218 SuggestionsService::~SuggestionsService() {} | 215 SuggestionsServiceImpl::~SuggestionsServiceImpl() {} |
219 | 216 |
220 bool SuggestionsService::FetchSuggestionsData() { | 217 bool SuggestionsServiceImpl::FetchSuggestionsData() { |
221 DCHECK(thread_checker_.CalledOnValidThread()); | 218 DCHECK(thread_checker_.CalledOnValidThread()); |
222 // If sync state allows, issue a network request to refresh the suggestions. | 219 // If sync state allows, issue a network request to refresh the suggestions. |
223 if (GetSyncState(sync_service_) != INITIALIZED_ENABLED_HISTORY) | 220 if (GetSyncState(sync_service_) != INITIALIZED_ENABLED_HISTORY) |
224 return false; | 221 return false; |
225 IssueRequestIfNoneOngoing(BuildSuggestionsURL()); | 222 IssueRequestIfNoneOngoing(BuildSuggestionsURL()); |
226 return true; | 223 return true; |
227 } | 224 } |
228 | 225 |
229 SuggestionsProfile SuggestionsService::GetSuggestionsDataFromCache() const { | 226 base::Optional<SuggestionsProfile> |
| 227 SuggestionsServiceImpl::GetSuggestionsDataFromCache() const { |
230 SuggestionsProfile suggestions; | 228 SuggestionsProfile suggestions; |
231 // In case of empty cache or error, |suggestions| stays empty. | 229 // In case of empty cache or error, return empty. |
232 suggestions_store_->LoadSuggestions(&suggestions); | 230 if (!suggestions_store_->LoadSuggestions(&suggestions)) { |
| 231 return base::Optional<SuggestionsProfile>(); |
| 232 } |
233 thumbnail_manager_->Initialize(suggestions); | 233 thumbnail_manager_->Initialize(suggestions); |
234 blacklist_store_->FilterSuggestions(&suggestions); | 234 blacklist_store_->FilterSuggestions(&suggestions); |
235 return suggestions; | 235 return base::Optional<SuggestionsProfile>(suggestions); |
236 } | 236 } |
237 | 237 |
238 std::unique_ptr<SuggestionsService::ResponseCallbackList::Subscription> | 238 std::unique_ptr<SuggestionsServiceImpl::ResponseCallbackList::Subscription> |
239 SuggestionsService::AddCallback(const ResponseCallback& callback) { | 239 SuggestionsServiceImpl::AddCallback(const ResponseCallback& callback) { |
240 return callback_list_.Add(callback); | 240 return callback_list_.Add(callback); |
241 } | 241 } |
242 | 242 |
243 void SuggestionsService::GetPageThumbnail(const GURL& url, | 243 void SuggestionsServiceImpl::GetPageThumbnail(const GURL& url, |
244 const BitmapCallback& callback) { | 244 const BitmapCallback& callback) { |
245 thumbnail_manager_->GetImageForURL(url, callback); | 245 thumbnail_manager_->GetImageForURL(url, callback); |
246 } | 246 } |
247 | 247 |
248 void SuggestionsService::GetPageThumbnailWithURL( | 248 void SuggestionsServiceImpl::GetPageThumbnailWithURL( |
249 const GURL& url, | 249 const GURL& url, |
250 const GURL& thumbnail_url, | 250 const GURL& thumbnail_url, |
251 const BitmapCallback& callback) { | 251 const BitmapCallback& callback) { |
252 thumbnail_manager_->AddImageURL(url, thumbnail_url); | 252 thumbnail_manager_->AddImageURL(url, thumbnail_url); |
253 GetPageThumbnail(url, callback); | 253 GetPageThumbnail(url, callback); |
254 } | 254 } |
255 | 255 |
256 bool SuggestionsService::BlacklistURL(const GURL& candidate_url) { | 256 bool SuggestionsServiceImpl::BlacklistURL(const GURL& candidate_url) { |
257 DCHECK(thread_checker_.CalledOnValidThread()); | 257 DCHECK(thread_checker_.CalledOnValidThread()); |
258 | 258 |
259 if (!blacklist_store_->BlacklistUrl(candidate_url)) | 259 if (!blacklist_store_->BlacklistUrl(candidate_url)) |
260 return false; | 260 return false; |
261 | 261 |
262 callback_list_.Notify(GetSuggestionsDataFromCache()); | 262 callback_list_.Notify( |
| 263 GetSuggestionsDataFromCache().value_or(SuggestionsProfile())); |
263 | 264 |
264 // Blacklist uploads are scheduled on any request completion, so only schedule | 265 // Blacklist uploads are scheduled on any request completion, so only schedule |
265 // an upload if there is no ongoing request. | 266 // an upload if there is no ongoing request. |
266 if (!pending_request_.get()) | 267 if (!pending_request_.get()) |
267 ScheduleBlacklistUpload(); | 268 ScheduleBlacklistUpload(); |
268 | 269 |
269 return true; | 270 return true; |
270 } | 271 } |
271 | 272 |
272 bool SuggestionsService::UndoBlacklistURL(const GURL& url) { | 273 bool SuggestionsServiceImpl::UndoBlacklistURL(const GURL& url) { |
273 DCHECK(thread_checker_.CalledOnValidThread()); | 274 DCHECK(thread_checker_.CalledOnValidThread()); |
274 TimeDelta time_delta; | 275 TimeDelta time_delta; |
275 if (blacklist_store_->GetTimeUntilURLReadyForUpload(url, &time_delta) && | 276 if (blacklist_store_->GetTimeUntilURLReadyForUpload(url, &time_delta) && |
276 time_delta > TimeDelta::FromSeconds(0) && | 277 time_delta > TimeDelta::FromSeconds(0) && |
277 blacklist_store_->RemoveUrl(url)) { | 278 blacklist_store_->RemoveUrl(url)) { |
278 // The URL was not yet candidate for upload to the server and could be | 279 // The URL was not yet candidate for upload to the server and could be |
279 // removed from the blacklist. | 280 // removed from the blacklist. |
280 callback_list_.Notify(GetSuggestionsDataFromCache()); | 281 callback_list_.Notify( |
| 282 GetSuggestionsDataFromCache().value_or(SuggestionsProfile())); |
281 return true; | 283 return true; |
282 } | 284 } |
283 return false; | 285 return false; |
284 } | 286 } |
285 | 287 |
286 void SuggestionsService::ClearBlacklist() { | 288 void SuggestionsServiceImpl::ClearBlacklist() { |
287 DCHECK(thread_checker_.CalledOnValidThread()); | 289 DCHECK(thread_checker_.CalledOnValidThread()); |
288 blacklist_store_->ClearBlacklist(); | 290 blacklist_store_->ClearBlacklist(); |
289 callback_list_.Notify(GetSuggestionsDataFromCache()); | 291 callback_list_.Notify( |
| 292 GetSuggestionsDataFromCache().value_or(SuggestionsProfile())); |
290 IssueRequestIfNoneOngoing(BuildSuggestionsBlacklistClearURL()); | 293 IssueRequestIfNoneOngoing(BuildSuggestionsBlacklistClearURL()); |
291 } | 294 } |
292 | 295 |
293 // static | 296 // static |
294 bool SuggestionsService::GetBlacklistedUrl(const net::URLFetcher& request, | 297 bool SuggestionsServiceImpl::GetBlacklistedUrl(const net::URLFetcher& request, |
295 GURL* url) { | 298 GURL* url) { |
296 bool is_blacklist_request = base::StartsWith( | 299 bool is_blacklist_request = base::StartsWith( |
297 request.GetOriginalURL().spec(), BuildSuggestionsBlacklistURLPrefix(), | 300 request.GetOriginalURL().spec(), BuildSuggestionsBlacklistURLPrefix(), |
298 base::CompareCase::SENSITIVE); | 301 base::CompareCase::SENSITIVE); |
299 if (!is_blacklist_request) return false; | 302 if (!is_blacklist_request) |
| 303 return false; |
300 | 304 |
301 // Extract the blacklisted URL from the blacklist request. | 305 // Extract the blacklisted URL from the blacklist request. |
302 std::string blacklisted; | 306 std::string blacklisted; |
303 if (!net::GetValueForKeyInQuery( | 307 if (!net::GetValueForKeyInQuery(request.GetOriginalURL(), |
304 request.GetOriginalURL(), | 308 kSuggestionsBlacklistURLParam, |
305 kSuggestionsBlacklistURLParam, | 309 &blacklisted)) { |
306 &blacklisted)) { | |
307 return false; | 310 return false; |
308 } | 311 } |
309 | 312 |
310 GURL blacklisted_url(blacklisted); | 313 GURL blacklisted_url(blacklisted); |
311 blacklisted_url.Swap(url); | 314 blacklisted_url.Swap(url); |
312 return true; | 315 return true; |
313 } | 316 } |
314 | 317 |
315 // static | 318 // static |
316 void SuggestionsService::RegisterProfilePrefs( | 319 void SuggestionsServiceImpl::RegisterProfilePrefs( |
317 user_prefs::PrefRegistrySyncable* registry) { | 320 user_prefs::PrefRegistrySyncable* registry) { |
318 SuggestionsStore::RegisterProfilePrefs(registry); | 321 SuggestionsStore::RegisterProfilePrefs(registry); |
319 BlacklistStore::RegisterProfilePrefs(registry); | 322 BlacklistStore::RegisterProfilePrefs(registry); |
320 } | 323 } |
321 | 324 |
322 // static | 325 // static |
323 GURL SuggestionsService::BuildSuggestionsURL() { | 326 GURL SuggestionsServiceImpl::BuildSuggestionsURL() { |
324 return GURL(base::StringPrintf(kSuggestionsURLFormat, | 327 return GURL(base::StringPrintf( |
325 GetGoogleBaseURL().spec().c_str(), | 328 kSuggestionsURLFormat, GetGoogleBaseURL().spec().c_str(), kDeviceType)); |
326 kDeviceType)); | |
327 } | 329 } |
328 | 330 |
329 // static | 331 // static |
330 std::string SuggestionsService::BuildSuggestionsBlacklistURLPrefix() { | 332 std::string SuggestionsServiceImpl::BuildSuggestionsBlacklistURLPrefix() { |
331 return base::StringPrintf(kSuggestionsBlacklistURLPrefixFormat, | 333 return base::StringPrintf(kSuggestionsBlacklistURLPrefixFormat, |
332 GetGoogleBaseURL().spec().c_str(), kDeviceType); | 334 GetGoogleBaseURL().spec().c_str(), kDeviceType); |
333 } | 335 } |
334 | 336 |
335 // static | 337 // static |
336 GURL SuggestionsService::BuildSuggestionsBlacklistURL( | 338 GURL SuggestionsServiceImpl::BuildSuggestionsBlacklistURL( |
337 const GURL& candidate_url) { | 339 const GURL& candidate_url) { |
338 return GURL(BuildSuggestionsBlacklistURLPrefix() + | 340 return GURL(BuildSuggestionsBlacklistURLPrefix() + |
339 net::EscapeQueryParamValue(candidate_url.spec(), true)); | 341 net::EscapeQueryParamValue(candidate_url.spec(), true)); |
340 } | 342 } |
341 | 343 |
342 // static | 344 // static |
343 GURL SuggestionsService::BuildSuggestionsBlacklistClearURL() { | 345 GURL SuggestionsServiceImpl::BuildSuggestionsBlacklistClearURL() { |
344 return GURL(base::StringPrintf(kSuggestionsBlacklistClearURLFormat, | 346 return GURL(base::StringPrintf(kSuggestionsBlacklistClearURLFormat, |
345 GetGoogleBaseURL().spec().c_str(), | 347 GetGoogleBaseURL().spec().c_str(), |
346 kDeviceType)); | 348 kDeviceType)); |
347 } | 349 } |
348 | 350 |
349 void SuggestionsService::OnStateChanged() { | 351 void SuggestionsServiceImpl::OnStateChanged() { |
350 switch (GetSyncState(sync_service_)) { | 352 switch (GetSyncState(sync_service_)) { |
351 case SYNC_OR_HISTORY_SYNC_DISABLED: | 353 case SYNC_OR_HISTORY_SYNC_DISABLED: |
352 // Cancel any ongoing request, to stop interacting with the server. | 354 // Cancel any ongoing request, to stop interacting with the server. |
353 pending_request_.reset(nullptr); | 355 pending_request_.reset(nullptr); |
354 suggestions_store_->ClearSuggestions(); | 356 suggestions_store_->ClearSuggestions(); |
355 callback_list_.Notify(SuggestionsProfile()); | 357 callback_list_.Notify(SuggestionsProfile()); |
356 break; | 358 break; |
357 case NOT_INITIALIZED_ENABLED: | 359 case NOT_INITIALIZED_ENABLED: |
358 // Keep the cache (if any), but don't refresh. | 360 // Keep the cache (if any), but don't refresh. |
359 break; | 361 break; |
360 case INITIALIZED_ENABLED_HISTORY: | 362 case INITIALIZED_ENABLED_HISTORY: |
361 // If we have any observers, issue a network request to refresh the | 363 // If we have any observers, issue a network request to refresh the |
362 // suggestions in the cache. | 364 // suggestions in the cache. |
363 if (!callback_list_.empty()) | 365 if (!callback_list_.empty()) |
364 IssueRequestIfNoneOngoing(BuildSuggestionsURL()); | 366 IssueRequestIfNoneOngoing(BuildSuggestionsURL()); |
365 break; | 367 break; |
366 } | 368 } |
367 } | 369 } |
368 | 370 |
369 void SuggestionsService::SetDefaultExpiryTimestamp( | 371 void SuggestionsServiceImpl::SetDefaultExpiryTimestamp( |
370 SuggestionsProfile* suggestions, | 372 SuggestionsProfile* suggestions, |
371 int64_t default_timestamp_usec) { | 373 int64_t default_timestamp_usec) { |
372 for (int i = 0; i < suggestions->suggestions_size(); ++i) { | 374 for (int i = 0; i < suggestions->suggestions_size(); ++i) { |
373 ChromeSuggestion* suggestion = suggestions->mutable_suggestions(i); | 375 ChromeSuggestion* suggestion = suggestions->mutable_suggestions(i); |
374 // Do not set expiry if the server has already provided a more specific | 376 // Do not set expiry if the server has already provided a more specific |
375 // expiry time for this suggestion. | 377 // expiry time for this suggestion. |
376 if (!suggestion->has_expiry_ts()) { | 378 if (!suggestion->has_expiry_ts()) { |
377 suggestion->set_expiry_ts(default_timestamp_usec); | 379 suggestion->set_expiry_ts(default_timestamp_usec); |
378 } | 380 } |
379 } | 381 } |
380 } | 382 } |
381 | 383 |
382 void SuggestionsService::IssueRequestIfNoneOngoing(const GURL& url) { | 384 void SuggestionsServiceImpl::IssueRequestIfNoneOngoing(const GURL& url) { |
383 // If there is an ongoing request, let it complete. | 385 // If there is an ongoing request, let it complete. |
384 if (pending_request_.get()) { | 386 if (pending_request_.get()) { |
385 return; | 387 return; |
386 } | 388 } |
387 // If there is an ongoing token request, also wait for that. | 389 // If there is an ongoing token request, also wait for that. |
388 if (token_fetcher_->HasPendingRequest()) { | 390 if (token_fetcher_->HasPendingRequest()) { |
389 return; | 391 return; |
390 } | 392 } |
391 token_fetcher_->GetAccessToken( | 393 token_fetcher_->GetAccessToken( |
392 base::Bind(&SuggestionsService::IssueSuggestionsRequest, | 394 base::Bind(&SuggestionsServiceImpl::IssueSuggestionsRequest, |
393 base::Unretained(this), url)); | 395 base::Unretained(this), url)); |
394 } | 396 } |
395 | 397 |
396 void SuggestionsService::IssueSuggestionsRequest( | 398 void SuggestionsServiceImpl::IssueSuggestionsRequest( |
397 const GURL& url, | 399 const GURL& url, |
398 const std::string& access_token) { | 400 const std::string& access_token) { |
399 if (access_token.empty()) { | 401 if (access_token.empty()) { |
400 UpdateBlacklistDelay(false); | 402 UpdateBlacklistDelay(false); |
401 ScheduleBlacklistUpload(); | 403 ScheduleBlacklistUpload(); |
402 return; | 404 return; |
403 } | 405 } |
404 pending_request_ = CreateSuggestionsRequest(url, access_token); | 406 pending_request_ = CreateSuggestionsRequest(url, access_token); |
405 pending_request_->Start(); | 407 pending_request_->Start(); |
406 last_request_started_time_ = TimeTicks::Now(); | 408 last_request_started_time_ = TimeTicks::Now(); |
407 } | 409 } |
408 | 410 |
409 std::unique_ptr<net::URLFetcher> SuggestionsService::CreateSuggestionsRequest( | 411 std::unique_ptr<net::URLFetcher> |
| 412 SuggestionsServiceImpl::CreateSuggestionsRequest( |
410 const GURL& url, | 413 const GURL& url, |
411 const std::string& access_token) { | 414 const std::string& access_token) { |
412 std::unique_ptr<net::URLFetcher> request = | 415 std::unique_ptr<net::URLFetcher> request = |
413 net::URLFetcher::Create(0, url, net::URLFetcher::GET, this); | 416 net::URLFetcher::Create(0, url, net::URLFetcher::GET, this); |
414 data_use_measurement::DataUseUserData::AttachToFetcher( | 417 data_use_measurement::DataUseUserData::AttachToFetcher( |
415 request.get(), data_use_measurement::DataUseUserData::SUGGESTIONS); | 418 request.get(), data_use_measurement::DataUseUserData::SUGGESTIONS); |
416 int load_flags = net::LOAD_DISABLE_CACHE | net::LOAD_DO_NOT_SEND_COOKIES | | 419 int load_flags = net::LOAD_DISABLE_CACHE | net::LOAD_DO_NOT_SEND_COOKIES | |
417 net::LOAD_DO_NOT_SAVE_COOKIES; | 420 net::LOAD_DO_NOT_SAVE_COOKIES; |
418 | 421 |
419 request->SetLoadFlags(load_flags); | 422 request->SetLoadFlags(load_flags); |
420 request->SetRequestContext(url_request_context_); | 423 request->SetRequestContext(url_request_context_); |
421 // Add Chrome experiment state to the request headers. | 424 // Add Chrome experiment state to the request headers. |
422 net::HttpRequestHeaders headers; | 425 net::HttpRequestHeaders headers; |
423 variations::AppendVariationHeaders(request->GetOriginalURL(), false, false, | 426 variations::AppendVariationHeaders(request->GetOriginalURL(), false, false, |
424 &headers); | 427 &headers); |
425 request->SetExtraRequestHeaders(headers.ToString()); | 428 request->SetExtraRequestHeaders(headers.ToString()); |
426 if (!access_token.empty()) { | 429 if (!access_token.empty()) { |
427 request->AddExtraRequestHeader( | 430 request->AddExtraRequestHeader( |
428 base::StringPrintf(kAuthorizationHeaderFormat, access_token.c_str())); | 431 base::StringPrintf(kAuthorizationHeaderFormat, access_token.c_str())); |
429 } | 432 } |
430 return request; | 433 return request; |
431 } | 434 } |
432 | 435 |
433 void SuggestionsService::OnURLFetchComplete(const net::URLFetcher* source) { | 436 void SuggestionsServiceImpl::OnURLFetchComplete(const net::URLFetcher* source) { |
434 DCHECK(thread_checker_.CalledOnValidThread()); | 437 DCHECK(thread_checker_.CalledOnValidThread()); |
435 DCHECK_EQ(pending_request_.get(), source); | 438 DCHECK_EQ(pending_request_.get(), source); |
436 | 439 |
437 // The fetcher will be deleted when the request is handled. | 440 // The fetcher will be deleted when the request is handled. |
438 std::unique_ptr<const net::URLFetcher> request(std::move(pending_request_)); | 441 std::unique_ptr<const net::URLFetcher> request(std::move(pending_request_)); |
439 | 442 |
440 const net::URLRequestStatus& request_status = request->GetStatus(); | 443 const net::URLRequestStatus& request_status = request->GetStatus(); |
441 if (request_status.status() != net::URLRequestStatus::SUCCESS) { | 444 if (request_status.status() != net::URLRequestStatus::SUCCESS) { |
442 // This represents network errors (i.e. the server did not provide a | 445 // This represents network errors (i.e. the server did not provide a |
443 // response). | 446 // response). |
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
486 int64_t now_usec = | 489 int64_t now_usec = |
487 (base::Time::NowFromSystemTime() - base::Time::UnixEpoch()) | 490 (base::Time::NowFromSystemTime() - base::Time::UnixEpoch()) |
488 .ToInternalValue(); | 491 .ToInternalValue(); |
489 SetDefaultExpiryTimestamp(&suggestions, now_usec + kDefaultExpiryUsec); | 492 SetDefaultExpiryTimestamp(&suggestions, now_usec + kDefaultExpiryUsec); |
490 PopulateExtraData(&suggestions); | 493 PopulateExtraData(&suggestions); |
491 suggestions_store_->StoreSuggestions(suggestions); | 494 suggestions_store_->StoreSuggestions(suggestions); |
492 } else { | 495 } else { |
493 LogResponseState(RESPONSE_INVALID); | 496 LogResponseState(RESPONSE_INVALID); |
494 } | 497 } |
495 | 498 |
496 callback_list_.Notify(GetSuggestionsDataFromCache()); | 499 callback_list_.Notify( |
| 500 GetSuggestionsDataFromCache().value_or(SuggestionsProfile())); |
497 | 501 |
498 UpdateBlacklistDelay(true); | 502 UpdateBlacklistDelay(true); |
499 ScheduleBlacklistUpload(); | 503 ScheduleBlacklistUpload(); |
500 } | 504 } |
501 | 505 |
502 void SuggestionsService::PopulateExtraData(SuggestionsProfile* suggestions) { | 506 void SuggestionsServiceImpl::PopulateExtraData( |
| 507 SuggestionsProfile* suggestions) { |
503 for (int i = 0; i < suggestions->suggestions_size(); ++i) { | 508 for (int i = 0; i < suggestions->suggestions_size(); ++i) { |
504 suggestions::ChromeSuggestion* s = suggestions->mutable_suggestions(i); | 509 suggestions::ChromeSuggestion* s = suggestions->mutable_suggestions(i); |
505 if (!s->has_favicon_url() || s->favicon_url().empty()) { | 510 if (!s->has_favicon_url() || s->favicon_url().empty()) { |
506 s->set_favicon_url(base::StringPrintf(kFaviconURL, s->url().c_str())); | 511 s->set_favicon_url(base::StringPrintf(kFaviconURL, s->url().c_str())); |
507 } | 512 } |
508 } | 513 } |
509 } | 514 } |
510 | 515 |
511 void SuggestionsService::Shutdown() { | 516 void SuggestionsServiceImpl::Shutdown() { |
512 // Cancel pending request. | 517 // Cancel pending request. |
513 pending_request_.reset(nullptr); | 518 pending_request_.reset(nullptr); |
514 } | 519 } |
515 | 520 |
516 void SuggestionsService::ScheduleBlacklistUpload() { | 521 void SuggestionsServiceImpl::ScheduleBlacklistUpload() { |
517 DCHECK(thread_checker_.CalledOnValidThread()); | 522 DCHECK(thread_checker_.CalledOnValidThread()); |
518 TimeDelta time_delta; | 523 TimeDelta time_delta; |
519 if (blacklist_store_->GetTimeUntilReadyForUpload(&time_delta)) { | 524 if (blacklist_store_->GetTimeUntilReadyForUpload(&time_delta)) { |
520 // Blacklist cache is not empty: schedule. | 525 // Blacklist cache is not empty: schedule. |
521 base::Closure blacklist_cb = | 526 base::Closure blacklist_cb = |
522 base::Bind(&SuggestionsService::UploadOneFromBlacklist, | 527 base::Bind(&SuggestionsServiceImpl::UploadOneFromBlacklist, |
523 weak_ptr_factory_.GetWeakPtr()); | 528 weak_ptr_factory_.GetWeakPtr()); |
524 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( | 529 base::ThreadTaskRunnerHandle::Get()->PostDelayedTask( |
525 FROM_HERE, blacklist_cb, time_delta + scheduling_delay_); | 530 FROM_HERE, blacklist_cb, time_delta + scheduling_delay_); |
526 } | 531 } |
527 } | 532 } |
528 | 533 |
529 void SuggestionsService::UploadOneFromBlacklist() { | 534 void SuggestionsServiceImpl::UploadOneFromBlacklist() { |
530 DCHECK(thread_checker_.CalledOnValidThread()); | 535 DCHECK(thread_checker_.CalledOnValidThread()); |
531 | 536 |
532 GURL blacklisted_url; | 537 GURL blacklisted_url; |
533 if (blacklist_store_->GetCandidateForUpload(&blacklisted_url)) { | 538 if (blacklist_store_->GetCandidateForUpload(&blacklisted_url)) { |
534 // Issue a blacklisting request. Even if this request ends up not being sent | 539 // Issue a blacklisting request. Even if this request ends up not being sent |
535 // because of an ongoing request, a blacklist request is later scheduled. | 540 // because of an ongoing request, a blacklist request is later scheduled. |
536 IssueRequestIfNoneOngoing(BuildSuggestionsBlacklistURL(blacklisted_url)); | 541 IssueRequestIfNoneOngoing(BuildSuggestionsBlacklistURL(blacklisted_url)); |
537 return; | 542 return; |
538 } | 543 } |
539 | 544 |
540 // Even though there's no candidate for upload, the blacklist might not be | 545 // Even though there's no candidate for upload, the blacklist might not be |
541 // empty. | 546 // empty. |
542 ScheduleBlacklistUpload(); | 547 ScheduleBlacklistUpload(); |
543 } | 548 } |
544 | 549 |
545 void SuggestionsService::UpdateBlacklistDelay(bool last_request_successful) { | 550 void SuggestionsServiceImpl::UpdateBlacklistDelay( |
| 551 bool last_request_successful) { |
546 DCHECK(thread_checker_.CalledOnValidThread()); | 552 DCHECK(thread_checker_.CalledOnValidThread()); |
547 | 553 |
548 if (last_request_successful) { | 554 if (last_request_successful) { |
549 scheduling_delay_ = TimeDelta::FromSeconds(kDefaultSchedulingDelaySec); | 555 scheduling_delay_ = TimeDelta::FromSeconds(kDefaultSchedulingDelaySec); |
550 } else { | 556 } else { |
551 TimeDelta candidate_delay = | 557 TimeDelta candidate_delay = |
552 scheduling_delay_ * kSchedulingBackoffMultiplier; | 558 scheduling_delay_ * kSchedulingBackoffMultiplier; |
553 if (candidate_delay < TimeDelta::FromSeconds(kSchedulingMaxDelaySec)) | 559 if (candidate_delay < TimeDelta::FromSeconds(kSchedulingMaxDelaySec)) |
554 scheduling_delay_ = candidate_delay; | 560 scheduling_delay_ = candidate_delay; |
555 } | 561 } |
556 } | 562 } |
557 | 563 |
558 } // namespace suggestions | 564 } // namespace suggestions |
OLD | NEW |