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
3// found in the LICENSE file.
4
5#ifndef COMPONENTS_SUGGESTIONS_SUGGESTIONS_SERVICE_H_
6#define COMPONENTS_SUGGESTIONS_SUGGESTIONS_SERVICE_H_
7
8#include <string>
9#include <vector>
10
11#include "base/basictypes.h"
12#include "base/callback.h"
13#include "base/cancelable_callback.h"
14#include "base/gtest_prod_util.h"
15#include "base/memory/scoped_ptr.h"
16#include "base/memory/weak_ptr.h"
17#include "base/threading/thread_checker.h"
18#include "base/time/time.h"
19#include "components/keyed_service/core/keyed_service.h"
20#include "components/suggestions/image_manager.h"
21#include "components/suggestions/proto/suggestions.pb.h"
22#include "components/suggestions/suggestions_utils.h"
23#include "net/url_request/url_fetcher_delegate.h"
24#include "ui/gfx/image/image_skia.h"
25#include "url/gurl.h"
26
27namespace net {
28class URLRequestContextGetter;
29}  // namespace net
30
31namespace user_prefs {
32class PrefRegistrySyncable;
33}  // namespace user_prefs
34
35namespace suggestions {
36
37class BlacklistStore;
38class SuggestionsStore;
39
40extern const char kSuggestionsFieldTrialName[];
41extern const char kSuggestionsFieldTrialURLParam[];
42extern const char kSuggestionsFieldTrialCommonParamsParam[];
43extern const char kSuggestionsFieldTrialBlacklistPathParam[];
44extern const char kSuggestionsFieldTrialBlacklistUrlParam[];
45extern const char kSuggestionsFieldTrialStateParam[];
46extern const char kSuggestionsFieldTrialControlParam[];
47extern const char kSuggestionsFieldTrialStateEnabled[];
48extern const int64 kDefaultExpiryUsec;
49
50// An interface to fetch server suggestions asynchronously.
51class SuggestionsService : public KeyedService, public net::URLFetcherDelegate {
52 public:
53  typedef base::Callback<void(const SuggestionsProfile&)> ResponseCallback;
54
55  SuggestionsService(
56      net::URLRequestContextGetter* url_request_context,
57      scoped_ptr<SuggestionsStore> suggestions_store,
58      scoped_ptr<ImageManager> thumbnail_manager,
59      scoped_ptr<BlacklistStore> blacklist_store);
60  virtual ~SuggestionsService();
61
62  // Whether this service is enabled.
63  static bool IsEnabled();
64
65  // Whether the user is part of a control group.
66  static bool IsControlGroup();
67
68  // Request suggestions data, which will be passed to |callback|. |sync_state|
69  // will influence the behavior of this function (see SyncState definition).
70  //
71  // |sync_state| must be specified based on the current state of the system
72  // (see suggestions::GetSyncState). Callers should call this function again if
73  // sync state changes.
74  //
75  // If state allows for a network request, it is initiated unless a pending one
76  // exists. To prevent multiple requests, all |callback|s are placed in a queue
77  // and are updated simultaneously when the fetch completes. Also posts a task
78  // to execute OnRequestTimeout if the request hasn't completed in a given
79  // amount of time.
80  void FetchSuggestionsData(SyncState sync_state,
81                            ResponseCallback callback);
82
83  // Retrieves stored thumbnail for website |url| asynchronously. Calls
84  // |callback| with Bitmap pointer if found, and NULL otherwise.
85  void GetPageThumbnail(
86      const GURL& url,
87      base::Callback<void(const GURL&, const SkBitmap*)> callback);
88
89  // Issue a blacklist request. If there is already a blacklist request
90  // in flight, the new blacklist request is ignored.
91  void BlacklistURL(const GURL& candidate_url,
92                    const ResponseCallback& callback);
93
94  // Determines which URL a blacklist request was for, irrespective of the
95  // request's status. Returns false if |request| is not a blacklist request.
96  static bool GetBlacklistedUrl(const net::URLFetcher& request, GURL* url);
97
98  // Register SuggestionsService related prefs in the Profile prefs.
99  static void RegisterProfilePrefs(user_prefs::PrefRegistrySyncable* registry);
100
101  // Sets default timestamp for suggestions which do not have expiry timestamp.
102  void SetDefaultExpiryTimestamp(SuggestionsProfile* suggestions,
103                                 int64 timestamp_usec);
104 private:
105  friend class SuggestionsServiceTest;
106  FRIEND_TEST_ALL_PREFIXES(SuggestionsServiceTest, BlacklistURLFails);
107  FRIEND_TEST_ALL_PREFIXES(SuggestionsServiceTest, FetchSuggestionsData);
108  FRIEND_TEST_ALL_PREFIXES(SuggestionsServiceTest, UpdateBlacklistDelay);
109
110  // Similar to FetchSuggestionsData but doesn't post a task to execute
111  // OnDelaySinceFetch.
112  void FetchSuggestionsDataNoTimeout(ResponseCallback callback);
113
114  // Issue a request.
115  void IssueRequest(const GURL& url);
116
117  // Creates a request to the suggestions service, properly setting headers.
118  net::URLFetcher* CreateSuggestionsRequest(const GURL& url);
119
120  // Called to service the requestors if the issued suggestions request has
121  // not completed in a given amount of time.
122  virtual void OnRequestTimeout();
123
124  // net::URLFetcherDelegate implementation.
125  // Called when fetch request completes. Parses the received suggestions data,
126  // and dispatches them to callbacks stored in queue.
127  virtual void OnURLFetchComplete(const net::URLFetcher* source) OVERRIDE;
128
129  // KeyedService implementation.
130  virtual void Shutdown() OVERRIDE;
131
132  // Load the cached suggestions and service the requestors with them.
133  void ServeFromCache();
134
135  // Apply the local blacklist to |suggestions|, then serve the requestors.
136  void FilterAndServe(SuggestionsProfile* suggestions);
137
138  // Schedule a blacklisting request if the local blacklist isn't empty.
139  // |last_request_successful| is used for exponentially backing off when
140  // requests fail.
141  void ScheduleBlacklistUpload(bool last_request_successful);
142
143  // If the local blacklist isn't empty, pick a URL from it and issue a
144  // blacklist request for it.
145  void UploadOneFromBlacklist();
146
147  // Updates |blacklist_delay_sec_| based on the success of the last request.
148  void UpdateBlacklistDelay(bool last_request_successful);
149
150  // Test seams.
151  int blacklist_delay() const { return blacklist_delay_sec_; }
152  void set_blacklist_delay(int delay) { blacklist_delay_sec_ = delay; }
153
154  base::ThreadChecker thread_checker_;
155
156  // The cache for the suggestions.
157  scoped_ptr<SuggestionsStore> suggestions_store_;
158
159  // The local cache for temporary blacklist, until uploaded to the server.
160  scoped_ptr<BlacklistStore> blacklist_store_;
161
162  // Contains the current suggestions fetch request. Will only have a value
163  // while a request is pending, and will be reset by |OnURLFetchComplete|.
164  scoped_ptr<net::URLFetcher> pending_request_;
165
166  // A closure that is run on a timeout from issuing the suggestions fetch
167  // request, if the request hasn't completed.
168  scoped_ptr<base::CancelableClosure> pending_timeout_closure_;
169
170  // The start time of the previous suggestions request. This is used to measure
171  // the latency of requests. Initially zero.
172  base::TimeTicks last_request_started_time_;
173
174  // The URL to fetch suggestions data from.
175  GURL suggestions_url_;
176
177  // Prefix for building the blacklisting URL.
178  std::string blacklist_url_prefix_;
179
180  // Queue of callbacks. These are flushed when fetch request completes.
181  std::vector<ResponseCallback> waiting_requestors_;
182
183  // Used to obtain server thumbnails, if available.
184  scoped_ptr<ImageManager> thumbnail_manager_;
185
186  net::URLRequestContextGetter* url_request_context_;
187
188  // Delay used when scheduling a blacklisting task.
189  int blacklist_delay_sec_;
190
191  // Timeout (in ms) before serving requestors after a fetch suggestions request
192  // has been issued.
193  int request_timeout_ms_;
194
195  // For callbacks may be run after destruction.
196  base::WeakPtrFactory<SuggestionsService> weak_ptr_factory_;
197
198  DISALLOW_COPY_AND_ASSIGN(SuggestionsService);
199};
200
201}  // namespace suggestions
202
203#endif  // COMPONENTS_SUGGESTIONS_SUGGESTIONS_SERVICE_H_
204