1 // Copyright (c) 2012 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_HISTORY_CORE_BROWSER_EXPIRE_HISTORY_BACKEND_H_
6 #define COMPONENTS_HISTORY_CORE_BROWSER_EXPIRE_HISTORY_BACKEND_H_
7 
8 #include <map>
9 #include <memory>
10 #include <set>
11 #include <vector>
12 
13 #include "base/containers/queue.h"
14 #include "base/gtest_prod_util.h"
15 #include "base/macros.h"
16 #include "base/memory/weak_ptr.h"
17 #include "base/time/time.h"
18 #include "components/history/core/browser/history_types.h"
19 
20 class GURL;
21 
22 namespace base {
23 class SequencedTaskRunner;
24 }
25 
26 namespace favicon {
27 class FaviconDatabase;
28 }
29 
30 namespace history {
31 
32 class HistoryBackendClient;
33 class HistoryBackendNotifier;
34 class HistoryDatabase;
35 
36 // Encapsulates visit expiration criteria and type of visits to expire.
37 class ExpiringVisitsReader {
38  public:
~ExpiringVisitsReader()39   virtual ~ExpiringVisitsReader() {}
40   // Populates |visits| from |db|, using provided |end_time| and |max_visits|
41   // cap.
42   virtual bool Read(base::Time end_time, HistoryDatabase* db,
43                     VisitVector* visits, int max_visits) const = 0;
44 };
45 
46 typedef std::vector<const ExpiringVisitsReader*> ExpiringVisitsReaders;
47 
48 namespace internal {
49 // The minimum number of days since last use for an icon to be considered old.
50 extern const int kOnDemandFaviconIsOldAfterDays;
51 }  // namespace internal
52 
53 // Helper component to HistoryBackend that manages expiration and deleting of
54 // history.
55 //
56 // It will automatically start periodically expiring old history once you call
57 // StartExpiringOldStuff().
58 class ExpireHistoryBackend {
59  public:
60   // The delegate pointer must be non-null. We will NOT take ownership of it.
61   // HistoryBackendClient may be null. The HistoryBackendClient is used when
62   // expiring URLS so that we don't remove any URLs or favicons that are
63   // bookmarked or have a credential saved on (visits are removed though).
64   ExpireHistoryBackend(HistoryBackendNotifier* notifier,
65                        HistoryBackendClient* backend_client,
66                        scoped_refptr<base::SequencedTaskRunner> task_runner);
67   ~ExpireHistoryBackend();
68 
69   // Completes initialization by setting the databases that this class will use.
70   void SetDatabases(HistoryDatabase* main_db,
71                     favicon::FaviconDatabase* favicon_db);
72 
73   // Begins periodic expiration of history older than the given threshold. This
74   // will continue until the object is deleted.
75   void StartExpiringOldStuff(base::TimeDelta expiration_threshold);
76 
77   // Deletes everything associated with a URL until |end_time|.
78   void DeleteURL(const GURL& url, base::Time end_time);
79 
80   // Deletes everything associated with each URL in the list until |end_time|.
81   void DeleteURLs(const std::vector<GURL>& url, base::Time end_time);
82 
83   // Removes all visits to restrict_urls (or all URLs if empty) in the given
84   // time range, updating the URLs accordingly.
85   void ExpireHistoryBetween(const std::set<GURL>& restrict_urls,
86                             base::Time begin_time,
87                             base::Time end_time,
88                             bool user_initiated);
89 
90   // Removes all visits to all URLs with the given times, updating the
91   // URLs accordingly.  |times| must be in reverse chronological order
92   // and not contain any duplicates.
93   void ExpireHistoryForTimes(const std::vector<base::Time>& times);
94 
95   // Removes the given list of visits, updating the URLs accordingly (similar to
96   // ExpireHistoryBetween(), but affecting a specific set of visits).
97   void ExpireVisits(const VisitVector& visits);
98 
99   // Expires all visits before and including the given time, updating the URLs
100   // accordingly.
101   void ExpireHistoryBeforeForTesting(base::Time end_time);
102 
103   // Clears all old on-demand favicons. Fails silently (we don't care about
104   // favicons so much, so don't want to stop everything if it fails).
105   void ClearOldOnDemandFaviconsIfPossible(base::Time expiration_threshold);
106 
107   // Returns the current cut-off time before which we will start expiring stuff.
108   // Note that this as an absolute time rather than a delta, so the caller
109   // should not save it.
GetCurrentExpirationTime()110   base::Time GetCurrentExpirationTime() const {
111     return base::Time::Now() - expiration_threshold_;
112   }
113 
114  private:
115   FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, DeleteFaviconsIfPossible);
116   FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, ExpireSomeOldHistory);
117   FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, ExpiringVisitsReader);
118   FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest, ExpireSomeOldHistoryWithSource);
119   FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest,
120                            ClearOldOnDemandFaviconsDoesNotDeleteStarred);
121   FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest,
122                            ClearOldOnDemandFaviconsDoesDeleteUnstarred);
123   FRIEND_TEST_ALL_PREFIXES(ExpireHistoryTest,
124                            ClearOldOnDemandFaviconsDoesDeleteAfterLongDelay);
125   FRIEND_TEST_ALL_PREFIXES(
126       ExpireHistoryTest,
127       ClearOldOnDemandFaviconsDoesNotDeleteAfterShortDelay);
128 
129   struct DeleteEffects {
130     DeleteEffects();
131     ~DeleteEffects();
132 
133     // The time range affected. These can be is_null() to be unbounded in one
134     // or both directions.
135     base::Time begin_time, end_time;
136 
137     // The unique URL rows affected by this delete.
138     std::map<URLID, URLRow> affected_urls;
139 
140     // The URLs modified, but not deleted, during this operation.
141     URLRows modified_urls;
142 
143     // The URLs deleted during this operation.
144     URLRows deleted_urls;
145 
146     // All favicon IDs that the deleted URLs had. Favicons will be shared
147     // between all URLs with the same favicon, so this is the set of IDs that we
148     // will need to check when the delete operations are complete.
149     std::set<favicon_base::FaviconID> affected_favicons;
150 
151     // All favicon urls that were deleted from the favicon db.
152     std::set<GURL> deleted_favicons;
153   };
154 
155   // Returns a vector with all visits that eventually redirect to |visits|.
156   VisitVector GetVisitsAndRedirectParents(const VisitVector& visits);
157 
158   // Deletes the visit-related stuff for all the visits in the given list, and
159   // adds the rows for unique URLs affected to the affected_urls list in
160   // the dependencies structure.
161   void DeleteVisitRelatedInfo(const VisitVector& visits,
162                               DeleteEffects* effects);
163 
164   // Finds or deletes dependency information for the given URL. Information that
165   // is specific to this URL (URL row, favicons, etc.) is deleted.
166   //
167   // This does not affect the visits! This is used for expiration as well as
168   // deleting from the UI, and they handle visits differently.
169   //
170   // Other information will be collected and returned in the output containers.
171   // This includes some of the things deleted that are needed elsewhere, plus
172   // some things like favicons that could be shared by many URLs, and need to
173   // be checked for deletion (this allows us to delete many URLs with only one
174   // check for shared information at the end).
175   //
176   // Assumes the main_db_ is non-NULL.
177   //
178   // NOTE: If the url is pinned, we keep the favicons.
179   void DeleteOneURL(const URLRow& url_row,
180                     bool is_pinned,
181                     DeleteEffects* effects);
182 
183   // Deletes all favicons associated with |gurl|.
184   void DeleteIcons(const GURL& gurl, DeleteEffects* effects);
185 
186   // Deletes all the URLs in the given vector and handles their dependencies.
187   // This will delete starred URLs.
188   void DeleteURLs(const URLRows& urls, DeleteEffects* effects);
189 
190   // Expiration involves removing visits, then propagating the visits out from
191   // there and delete any orphaned URLs. These will be added to the deleted URLs
192   // field of the dependencies and DeleteOneURL will handle deleting out from
193   // there. This function does not handle favicons.
194   //
195   // When a URL is not deleted, the last visit time and the visit and typed
196   // counts will be updated.
197   //
198   // The visits in the given vector should have already been deleted from the
199   // database, and the list of affected URLs already be filled into
200   // |depenencies->affected_urls|.
201   //
202   // Starred URLs will not be deleted. The information in the dependencies that
203   // DeleteOneURL fills in will be updated, and this function will also delete
204   // any now-unused favicons.
205   void ExpireURLsForVisits(const VisitVector& visits, DeleteEffects* effects);
206 
207   // Enum representing what type of action resulted in the history DB deletion.
208   enum DeletionType {
209     // User initiated the deletion from the History UI.
210     DELETION_USER_INITIATED,
211     // History data was automatically expired due to being more than 90 days
212     // old.
213     DELETION_EXPIRED
214   };
215 
216   void ExpireVisitsInternal(const VisitVector& visits,
217                             const DeletionTimeRange& time_range,
218                             const std::set<GURL>& restrict_urls,
219                             DeletionType type);
220 
221   // Deletes the favicons listed in |effects->affected_favicons| if they are
222   // unused. Fails silently (we don't care about favicons so much, so don't want
223   // to stop everything if it fails). Fills |expired_favicons| with the set of
224   // favicon urls that no longer have associated visits and were therefore
225   // expired.
226   void DeleteFaviconsIfPossible(DeleteEffects* effects);
227 
228   // Broadcasts URL modified and deleted notifications.
229   void BroadcastNotifications(DeleteEffects* effects,
230                               DeletionType type,
231                               const DeletionTimeRange& time_range,
232                               base::Optional<std::set<GURL>> restrict_urls);
233 
234   // Schedules a call to DoExpireIteration.
235   void ScheduleExpire();
236 
237   // Calls ExpireSomeOldHistory to expire some amount of old history, according
238   // to the items in work queue, and schedules another call to happen in the
239   // future.
240   void DoExpireIteration();
241 
242   // Tries to expire the oldest |max_visits| visits from history that are older
243   // than |time_threshold|. The return value indicates if we think there might
244   // be more history to expire with the current time threshold (it does not
245   // indicate success or failure).
246   bool ExpireSomeOldHistory(base::Time end_time,
247                              const ExpiringVisitsReader* reader,
248                              int max_visits);
249 
250   // Tries to detect possible bad history or inconsistencies in the database
251   // and deletes items. For example, URLs with no visits.
252   void ParanoidExpireHistory();
253 
254   // Initializes periodic expiration work queue by populating it with with tasks
255   // for all known readers.
256   void InitWorkQueue();
257 
258   // Returns the reader for all visits. This method is only used by the unit
259   // tests.
260   const ExpiringVisitsReader* GetAllVisitsReader();
261 
262   // Returns the reader for AUTO_SUBFRAME visits. This method is only used by
263   // the unit tests.
264   const ExpiringVisitsReader* GetAutoSubframeVisitsReader();
265 
266   // Non-owning pointer to the notification delegate (guaranteed non-NULL).
267   HistoryBackendNotifier* notifier_;
268 
269   // Non-owning pointers to the databases we deal with (MAY BE NULL).
270   HistoryDatabase* main_db_;       // Main history database.
271   favicon::FaviconDatabase* favicon_db_;
272 
273   // The threshold for "old" history where we will automatically delete it.
274   base::TimeDelta expiration_threshold_;
275 
276   // The time at which we expect the expiration code to run.
277   base::Time expected_expiration_time_;
278 
279   // The lastly used threshold for "old" on-demand favicons.
280   base::Time last_on_demand_expiration_threshold_;
281 
282   // List of all distinct types of readers. This list is used to populate the
283   // work queue.
284   ExpiringVisitsReaders readers_;
285 
286   // Work queue for periodic expiration tasks, used by DoExpireIteration() to
287   // determine what to do at an iteration, as well as populate it for future
288   // iterations.
289   base::queue<const ExpiringVisitsReader*> work_queue_;
290 
291   // Readers for various types of visits.
292   // TODO(dglazkov): If you are adding another one, please consider reorganizing
293   // into a map.
294   std::unique_ptr<ExpiringVisitsReader> all_visits_reader_;
295   std::unique_ptr<ExpiringVisitsReader> auto_subframe_visits_reader_;
296 
297   // The HistoryBackendClient; may be null.
298   HistoryBackendClient* backend_client_;
299 
300   scoped_refptr<base::SequencedTaskRunner> task_runner_;
301 
302   // Used to generate runnable methods to do timers on this class. They will be
303   // automatically canceled when this class is deleted.
304   base::WeakPtrFactory<ExpireHistoryBackend> weak_factory_{this};
305 
306   DISALLOW_COPY_AND_ASSIGN(ExpireHistoryBackend);
307 };
308 
309 }  // namespace history
310 
311 #endif  // COMPONENTS_HISTORY_CORE_BROWSER_EXPIRE_HISTORY_BACKEND_H_
312