Source code

Revision control

Other Tools

1
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
* License, v. 2.0. If a copy of the MPL was not distributed with this
4
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#ifndef nsNavHistory_h_
7
#define nsNavHistory_h_
8
9
#include "nsINavHistoryService.h"
10
#include "nsINavBookmarksService.h"
11
#include "nsIFaviconService.h"
12
13
#include "nsIObserverService.h"
14
#include "nsICollation.h"
15
#include "nsIStringBundle.h"
16
#include "nsITimer.h"
17
#include "nsMaybeWeakPtr.h"
18
#include "nsCategoryCache.h"
19
#include "nsNetCID.h"
20
#include "nsToolkitCompsCID.h"
21
#include "nsURIHashKey.h"
22
#include "nsTHashtable.h"
23
24
#include "nsNavHistoryResult.h"
25
#include "nsNavHistoryQuery.h"
26
#include "Database.h"
27
#include "mozilla/Attributes.h"
28
#include "mozilla/Atomics.h"
29
30
#ifdef XP_WIN
31
# include "WinUtils.h"
32
# include <wincrypt.h>
33
#endif
34
35
#define QUERYUPDATE_TIME 0
36
#define QUERYUPDATE_SIMPLE 1
37
#define QUERYUPDATE_COMPLEX 2
38
#define QUERYUPDATE_COMPLEX_WITH_BOOKMARKS 3
39
#define QUERYUPDATE_HOST 4
40
#define QUERYUPDATE_MOBILEPREF 5
41
#define QUERYUPDATE_NONE 6
42
43
// Clamp title and URL to generously large, but not too large, length.
44
// See bug 319004 for details.
45
#define URI_LENGTH_MAX 65536
46
#define TITLE_LENGTH_MAX 4096
47
48
// Microsecond timeout for "recent" events such as typed and bookmark following.
49
// If you typed it more than this time ago, it's not recent.
50
#define RECENT_EVENT_THRESHOLD PRTime((int64_t)15 * 60 * PR_USEC_PER_SEC)
51
52
// The preference we watch to know when the mobile bookmarks folder is filled by
53
// sync.
54
#define MOBILE_BOOKMARKS_PREF "browser.bookmarks.showMobileBookmarks"
55
56
// The guid of the mobile bookmarks virtual query.
57
#define MOBILE_BOOKMARKS_VIRTUAL_GUID "mobile_____v"
58
59
#define ROOT_GUID "root________"
60
#define MENU_ROOT_GUID "menu________"
61
#define TOOLBAR_ROOT_GUID "toolbar_____"
62
#define UNFILED_ROOT_GUID "unfiled_____"
63
#define TAGS_ROOT_GUID "tags________"
64
#define MOBILE_ROOT_GUID "mobile______"
65
66
class nsIAutoCompleteController;
67
class nsIEffectiveTLDService;
68
class nsIIDNService;
69
class nsNavHistory;
70
class PlacesSQLQueryBuilder;
71
72
// nsNavHistory
73
74
class nsNavHistory final : public nsSupportsWeakReference,
75
public nsINavHistoryService,
76
public nsIObserver,
77
public mozIStorageVacuumParticipant {
78
friend class PlacesSQLQueryBuilder;
79
80
public:
81
nsNavHistory();
82
83
NS_DECL_THREADSAFE_ISUPPORTS
84
NS_DECL_NSINAVHISTORYSERVICE
85
NS_DECL_NSIOBSERVER
86
NS_DECL_MOZISTORAGEVACUUMPARTICIPANT
87
88
/**
89
* Obtains the nsNavHistory object.
90
*/
91
static already_AddRefed<nsNavHistory> GetSingleton();
92
93
/**
94
* Initializes the nsNavHistory object. This should only be called once.
95
*/
96
nsresult Init();
97
98
/**
99
* Used by other components in the places directory such as the annotation
100
* service to get a reference to this history object. Returns a pointer to
101
* the service if it exists. Otherwise creates one. Returns nullptr on error.
102
*/
103
static nsNavHistory* GetHistoryService() {
104
if (!gHistoryService) {
105
nsCOMPtr<nsINavHistoryService> serv =
106
do_GetService(NS_NAVHISTORYSERVICE_CONTRACTID);
107
NS_ENSURE_TRUE(serv, nullptr);
108
NS_ASSERTION(gHistoryService, "Should have static instance pointer now");
109
}
110
return gHistoryService;
111
}
112
113
/**
114
* Used by other components in the places directory to get a reference to a
115
* const version of this history object.
116
*
117
* @return A pointer to a const version of the service if it exists,
118
* nullptr otherwise.
119
*/
120
static const nsNavHistory* GetConstHistoryService() {
121
const nsNavHistory* const history = gHistoryService;
122
return history;
123
}
124
125
/**
126
* Fetches the database id and the GUID associated to the given URI.
127
*
128
* @param aURI
129
* The page to look for.
130
* @param _pageId
131
* Will be set to the database id associated with the page.
132
* If the page doesn't exist, this will be zero.
133
* @param _GUID
134
* Will be set to the unique id associated with the page.
135
* If the page doesn't exist, this will be empty.
136
* @note This DOES NOT check for bad URLs other than that they're nonempty.
137
*/
138
nsresult GetIdForPage(nsIURI* aURI, int64_t* _pageId, nsCString& _GUID);
139
140
/**
141
* Fetches the database id and the GUID associated to the given URI, creating
142
* a new database entry if one doesn't exist yet.
143
*
144
* @param aURI
145
* The page to look for or create.
146
* @param _pageId
147
* Will be set to the database id associated with the page.
148
* @param _GUID
149
* Will be set to the unique id associated with the page.
150
* @note This DOES NOT check for bad URLs other than that they're nonempty.
151
* @note This DOES NOT update frecency of the page.
152
*/
153
nsresult GetOrCreateIdForPage(nsIURI* aURI, int64_t* _pageId,
154
nsCString& _GUID);
155
156
/**
157
* Asynchronously recalculates frecency for a given page.
158
*
159
* @param aPlaceId
160
* Place id to recalculate the frecency for.
161
* @note If the new frecency is a non-zero value it will also unhide the page,
162
* otherwise will reuse the old hidden value.
163
*/
164
nsresult UpdateFrecency(int64_t aPlaceId);
165
166
/**
167
* These functions return non-owning references to the locale-specific
168
* objects for places components.
169
*/
170
nsIStringBundle* GetBundle();
171
nsICollation* GetCollation();
172
void GetStringFromName(const char* aName, nsACString& aResult);
173
void GetAgeInDaysString(int32_t aInt, const char* aName, nsACString& aResult);
174
static void GetMonthName(const PRExplodedTime& aTime, nsACString& aResult);
175
static void GetMonthYear(const PRExplodedTime& aTime, nsACString& aResult);
176
177
// Returns whether history is enabled or not.
178
bool IsHistoryDisabled() { return !mHistoryEnabled; }
179
180
// Constants for the columns returned by the above statement.
181
static const int32_t kGetInfoIndex_PageID;
182
static const int32_t kGetInfoIndex_URL;
183
static const int32_t kGetInfoIndex_Title;
184
static const int32_t kGetInfoIndex_RevHost;
185
static const int32_t kGetInfoIndex_VisitCount;
186
static const int32_t kGetInfoIndex_VisitDate;
187
static const int32_t kGetInfoIndex_FaviconURL;
188
static const int32_t kGetInfoIndex_ItemId;
189
static const int32_t kGetInfoIndex_ItemDateAdded;
190
static const int32_t kGetInfoIndex_ItemLastModified;
191
static const int32_t kGetInfoIndex_ItemParentId;
192
static const int32_t kGetInfoIndex_ItemTags;
193
static const int32_t kGetInfoIndex_Frecency;
194
static const int32_t kGetInfoIndex_Hidden;
195
static const int32_t kGetInfoIndex_Guid;
196
static const int32_t kGetInfoIndex_VisitId;
197
static const int32_t kGetInfoIndex_FromVisitId;
198
static const int32_t kGetInfoIndex_VisitType;
199
200
int64_t GetTagsFolder();
201
202
// this actually executes a query and gives you results, it is used by
203
// nsNavHistoryQueryResultNode
204
nsresult GetQueryResults(nsNavHistoryQueryResultNode* aResultNode,
205
const RefPtr<nsNavHistoryQuery>& aQuery,
206
const RefPtr<nsNavHistoryQueryOptions>& aOptions,
207
nsCOMArray<nsNavHistoryResultNode>* aResults);
208
209
// Take a row of kGetInfoIndex_* columns and construct a ResultNode.
210
// The row must contain the full set of columns.
211
nsresult RowToResult(mozIStorageValueArray* aRow,
212
nsNavHistoryQueryOptions* aOptions,
213
nsNavHistoryResultNode** aResult);
214
nsresult QueryRowToResult(int64_t aItemId, const nsACString& aBookmarkGuid,
215
const nsACString& aURI, const nsACString& aTitle,
216
uint32_t aAccessCount, PRTime aTime,
217
nsNavHistoryResultNode** aNode);
218
219
nsresult VisitIdToResultNode(int64_t visitId,
220
nsNavHistoryQueryOptions* aOptions,
221
nsNavHistoryResultNode** aResult);
222
223
nsresult BookmarkIdToResultNode(int64_t aBookmarkId,
224
nsNavHistoryQueryOptions* aOptions,
225
nsNavHistoryResultNode** aResult);
226
nsresult URIToResultNode(nsIURI* aURI, nsNavHistoryQueryOptions* aOptions,
227
nsNavHistoryResultNode** aResult);
228
229
// used by other places components to send history notifications (for example,
230
// when the favicon has changed)
231
void SendPageChangedNotification(nsIURI* aURI, uint32_t aChangedAttribute,
232
const nsAString& aValue,
233
const nsACString& aGUID);
234
235
/**
236
* Returns current number of days stored in history.
237
*/
238
int32_t GetDaysOfHistory();
239
240
void DomainNameFromURI(nsIURI* aURI, nsACString& aDomainName);
241
static PRTime NormalizeTime(uint32_t aRelative, PRTime aOffset);
242
243
typedef nsDataHashtable<nsCStringHashKey, nsCString> StringHash;
244
245
/**
246
* Indicates if it is OK to notify history observers or not.
247
*
248
* @return true if it is OK to notify, false otherwise.
249
*/
250
bool canNotify() { return mCanNotify; }
251
252
enum RecentEventFlags {
253
RECENT_TYPED = 1 << 0, // User typed in URL recently
254
RECENT_ACTIVATED = 1 << 1, // User tapped URL link recently
255
RECENT_BOOKMARKED = 1 << 2 // User bookmarked URL recently
256
};
257
258
/**
259
* Returns any recent activity done with a URL.
260
* @return Any recent events associated with this URI. Each bit is set
261
* according to RecentEventFlags enum values.
262
*/
263
uint32_t GetRecentFlags(nsIURI* aURI);
264
265
/**
266
* Whether there are visits.
267
* Note: This may cause synchronous I/O.
268
*/
269
bool hasHistoryEntries();
270
271
/**
272
* Returns whether the specified url has a embed visit.
273
*
274
* @param aURI
275
* URI of the page.
276
* @return whether the page has a embed visit.
277
*/
278
bool hasEmbedVisit(nsIURI* aURI);
279
280
int32_t GetFrecencyAgedWeight(int32_t aAgeInDays) const {
281
if (aAgeInDays <= mFirstBucketCutoffInDays) {
282
return mFirstBucketWeight;
283
}
284
if (aAgeInDays <= mSecondBucketCutoffInDays) {
285
return mSecondBucketWeight;
286
}
287
if (aAgeInDays <= mThirdBucketCutoffInDays) {
288
return mThirdBucketWeight;
289
}
290
if (aAgeInDays <= mFourthBucketCutoffInDays) {
291
return mFourthBucketWeight;
292
}
293
return mDefaultWeight;
294
}
295
296
int32_t GetFrecencyBucketWeight(int32_t aBucketIndex) const {
297
switch (aBucketIndex) {
298
case 1:
299
return mFirstBucketWeight;
300
case 2:
301
return mSecondBucketWeight;
302
case 3:
303
return mThirdBucketWeight;
304
case 4:
305
return mFourthBucketWeight;
306
default:
307
return mDefaultWeight;
308
}
309
}
310
311
int32_t GetFrecencyTransitionBonus(int32_t aTransitionType, bool aVisited,
312
bool aRedirect = false) const {
313
if (aRedirect) {
314
return mRedirectSourceVisitBonus;
315
}
316
317
switch (aTransitionType) {
318
case nsINavHistoryService::TRANSITION_EMBED:
319
return mEmbedVisitBonus;
320
case nsINavHistoryService::TRANSITION_FRAMED_LINK:
321
return mFramedLinkVisitBonus;
322
case nsINavHistoryService::TRANSITION_LINK:
323
return mLinkVisitBonus;
324
case nsINavHistoryService::TRANSITION_TYPED:
325
return aVisited ? mTypedVisitBonus : mUnvisitedTypedBonus;
326
case nsINavHistoryService::TRANSITION_BOOKMARK:
327
return aVisited ? mBookmarkVisitBonus : mUnvisitedBookmarkBonus;
328
case nsINavHistoryService::TRANSITION_DOWNLOAD:
329
return mDownloadVisitBonus;
330
case nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT:
331
return mPermRedirectVisitBonus;
332
case nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY:
333
return mTempRedirectVisitBonus;
334
case nsINavHistoryService::TRANSITION_RELOAD:
335
return mReloadVisitBonus;
336
default:
337
// 0 == undefined (see bug #375777 for details)
338
NS_WARNING_ASSERTION(!aTransitionType,
339
"new transition but no bonus for frecency");
340
return mDefaultVisitBonus;
341
}
342
}
343
344
int32_t GetNumVisitsForFrecency() const { return mNumVisitsForFrecency; }
345
346
/**
347
* Updates and invalidates the mDaysOfHistory cache. Should be
348
* called whenever a visit is added.
349
*/
350
void UpdateDaysOfHistory(PRTime visitTime);
351
352
/**
353
* Fires onTitleChanged event to nsINavHistoryService observers
354
*/
355
void NotifyTitleChange(nsIURI* aURI, const nsString& title,
356
const nsACString& aGUID);
357
358
/**
359
* Fires onFrecencyChanged event to nsINavHistoryService observers
360
*/
361
void NotifyFrecencyChanged(const nsACString& aSpec, int32_t aNewFrecency,
362
const nsACString& aGUID, bool aHidden,
363
PRTime aLastVisitDate);
364
365
/**
366
* Fires onManyFrecenciesChanged event to nsINavHistoryService observers
367
*/
368
void NotifyManyFrecenciesChanged();
369
370
/**
371
* Posts a runnable to the main thread that calls NotifyFrecencyChanged.
372
*/
373
void DispatchFrecencyChangedNotification(const nsACString& aSpec,
374
int32_t aNewFrecency,
375
const nsACString& aGUID,
376
bool aHidden,
377
PRTime aLastVisitDate) const;
378
379
/**
380
* Returns true if frecency is currently being decayed.
381
*
382
* @return True if frecency is being decayed, false if not.
383
*/
384
bool IsFrecencyDecaying() const;
385
386
/**
387
* Store last insterted id for a table.
388
*/
389
static mozilla::Atomic<int64_t> sLastInsertedPlaceId;
390
static mozilla::Atomic<int64_t> sLastInsertedVisitId;
391
392
static void StoreLastInsertedId(const nsACString& aTable,
393
const int64_t aLastInsertedId);
394
395
#ifdef XP_WIN
396
/**
397
* Get the cached HCRYPTPROV initialized in the nsNavHistory constructor.
398
*/
399
nsresult GetCryptoProvider(HCRYPTPROV& aCryptoProvider) const {
400
NS_ENSURE_STATE(mCryptoProviderInitialized);
401
aCryptoProvider = mCryptoProvider;
402
return NS_OK;
403
}
404
#endif
405
406
static nsresult FilterResultSet(
407
nsNavHistoryQueryResultNode* aParentNode,
408
const nsCOMArray<nsNavHistoryResultNode>& aSet,
409
nsCOMArray<nsNavHistoryResultNode>* aFiltered,
410
const RefPtr<nsNavHistoryQuery>& aQuery,
411
nsNavHistoryQueryOptions* aOptions);
412
413
void DecayFrecencyCompleted(uint16_t reason);
414
415
private:
416
~nsNavHistory();
417
418
// used by GetHistoryService
419
static nsNavHistory* gHistoryService;
420
421
protected:
422
// Database handle.
423
RefPtr<mozilla::places::Database> mDB;
424
425
/**
426
* Loads all of the preferences that we use into member variables.
427
*
428
* @note If mPrefBranch is nullptr, this does nothing.
429
*/
430
void LoadPrefs();
431
432
/**
433
* Calculates and returns value for mCachedNow.
434
* This is an hack to avoid calling PR_Now() too often, as is the case when
435
* we're asked the ageindays of many history entries in a row. A timer is
436
* set which will clear our valid flag after a short timeout.
437
*/
438
PRTime GetNow();
439
PRTime mCachedNow;
440
nsCOMPtr<nsITimer> mExpireNowTimer;
441
/**
442
* Called when the cached now value is expired and needs renewal.
443
*/
444
static void expireNowTimerCallback(nsITimer* aTimer, void* aClosure);
445
446
nsresult ConstructQueryString(
447
const RefPtr<nsNavHistoryQuery>& aQuery,
448
const RefPtr<nsNavHistoryQueryOptions>& aOptions, nsCString& queryString,
449
bool& aParamsPresent, StringHash& aAddParams);
450
451
nsresult QueryToSelectClause(const RefPtr<nsNavHistoryQuery>& aQuery,
452
const RefPtr<nsNavHistoryQueryOptions>& aOptions,
453
nsCString* aClause);
454
nsresult BindQueryClauseParameters(
455
mozIStorageBaseStatement* statement,
456
const RefPtr<nsNavHistoryQuery>& aQuery,
457
const RefPtr<nsNavHistoryQueryOptions>& aOptions);
458
459
nsresult ResultsAsList(mozIStorageStatement* statement,
460
nsNavHistoryQueryOptions* aOptions,
461
nsCOMArray<nsNavHistoryResultNode>* aResults);
462
463
// observers
464
nsMaybeWeakPtrArray<nsINavHistoryObserver> mObservers;
465
466
// effective tld service
467
nsCOMPtr<nsIEffectiveTLDService> mTLDService;
468
nsCOMPtr<nsIIDNService> mIDNService;
469
470
// localization
471
nsCOMPtr<nsIStringBundle> mBundle;
472
nsCOMPtr<nsICollation> mCollation;
473
474
// recent events
475
typedef nsDataHashtable<nsCStringHashKey, int64_t> RecentEventHash;
476
RecentEventHash mRecentTyped;
477
RecentEventHash mRecentLink;
478
RecentEventHash mRecentBookmark;
479
480
bool CheckIsRecentEvent(RecentEventHash* hashTable, const nsACString& url);
481
void ExpireNonrecentEvents(RecentEventHash* hashTable);
482
483
// Whether history is enabled or not.
484
// Will mimic value of the places.history.enabled preference.
485
bool mHistoryEnabled;
486
487
// Frecency preferences.
488
int32_t mNumVisitsForFrecency;
489
int32_t mFirstBucketCutoffInDays;
490
int32_t mSecondBucketCutoffInDays;
491
int32_t mThirdBucketCutoffInDays;
492
int32_t mFourthBucketCutoffInDays;
493
int32_t mFirstBucketWeight;
494
int32_t mSecondBucketWeight;
495
int32_t mThirdBucketWeight;
496
int32_t mFourthBucketWeight;
497
int32_t mDefaultWeight;
498
int32_t mEmbedVisitBonus;
499
int32_t mFramedLinkVisitBonus;
500
int32_t mLinkVisitBonus;
501
int32_t mTypedVisitBonus;
502
int32_t mBookmarkVisitBonus;
503
int32_t mDownloadVisitBonus;
504
int32_t mPermRedirectVisitBonus;
505
int32_t mTempRedirectVisitBonus;
506
int32_t mRedirectSourceVisitBonus;
507
int32_t mDefaultVisitBonus;
508
int32_t mUnvisitedBookmarkBonus;
509
int32_t mUnvisitedTypedBonus;
510
int32_t mReloadVisitBonus;
511
512
uint32_t mDecayFrecencyPendingCount;
513
514
nsresult RecalculateOriginFrecencyStatsInternal();
515
516
// in nsNavHistoryQuery.cpp
517
nsresult TokensToQuery(
518
const nsTArray<mozilla::places::QueryKeyValuePair>& aTokens,
519
nsNavHistoryQuery* aQuery, nsNavHistoryQueryOptions* aOptions);
520
521
int64_t mTagsFolder;
522
523
int32_t mDaysOfHistory;
524
int64_t mLastCachedStartOfDay;
525
int64_t mLastCachedEndOfDay;
526
527
// Used to enable and disable the observer notifications
528
bool mCanNotify;
529
530
// Used to cache the call to CryptAcquireContext, which is expensive
531
// when called thousands of times
532
#ifdef XP_WIN
533
HCRYPTPROV mCryptoProvider;
534
bool mCryptoProviderInitialized;
535
#endif
536
};
537
538
#define PLACES_URI_PREFIX "place:"
539
540
/* Returns true if the given URI represents a history query. */
541
inline bool IsQueryURI(const nsCString& uri) {
542
return StringBeginsWith(uri, NS_LITERAL_CSTRING(PLACES_URI_PREFIX));
543
}
544
545
/* Extracts the query string from a query URI. */
546
inline const nsDependentCSubstring QueryURIToQuery(const nsCString& uri) {
547
NS_ASSERTION(IsQueryURI(uri), "should only be called for query URIs");
548
return Substring(uri, NS_LITERAL_CSTRING(PLACES_URI_PREFIX).Length());
549
}
550
551
#endif // nsNavHistory_h_