Sat, 03 Jan 2015 20:18:00 +0100
Conditionally enable double key logic according to:
private browsing mode or privacy.thirdparty.isolate preference and
implement in GetCookieStringCommon and FindCookie where it counts...
With some reservations of how to convince FindCookie users to test
condition and pass a nullptr when disabling double key logic.
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/. */
6 #ifndef nsNavHistory_h_
7 #define nsNavHistory_h_
9 #include "nsINavHistoryService.h"
10 #include "nsPIPlacesDatabase.h"
11 #include "nsPIPlacesHistoryListenersNotifier.h"
12 #include "nsIBrowserHistory.h"
13 #include "nsINavBookmarksService.h"
14 #include "nsIFaviconService.h"
16 #include "nsIObserverService.h"
17 #include "nsICollation.h"
18 #include "nsIStringBundle.h"
19 #include "nsITimer.h"
20 #include "nsMaybeWeakPtr.h"
21 #include "nsCategoryCache.h"
22 #include "nsNetCID.h"
23 #include "nsToolkitCompsCID.h"
24 #include "nsURIHashKey.h"
25 #include "nsTHashtable.h"
27 #include "nsNavHistoryResult.h"
28 #include "nsNavHistoryQuery.h"
29 #include "Database.h"
30 #include "mozilla/Attributes.h"
32 #define QUERYUPDATE_TIME 0
33 #define QUERYUPDATE_SIMPLE 1
34 #define QUERYUPDATE_COMPLEX 2
35 #define QUERYUPDATE_COMPLEX_WITH_BOOKMARKS 3
36 #define QUERYUPDATE_HOST 4
38 // Clamp title and URL to generously large, but not too large, length.
39 // See bug 319004 for details.
40 #define URI_LENGTH_MAX 65536
41 #define TITLE_LENGTH_MAX 4096
43 // Microsecond timeout for "recent" events such as typed and bookmark following.
44 // If you typed it more than this time ago, it's not recent.
45 #define RECENT_EVENT_THRESHOLD PRTime((int64_t)15 * 60 * PR_USEC_PER_SEC)
47 #ifdef MOZ_XUL
48 // Fired after autocomplete feedback has been updated.
49 #define TOPIC_AUTOCOMPLETE_FEEDBACK_UPDATED "places-autocomplete-feedback-updated"
50 #endif
52 // Fired after frecency has been updated.
53 #define TOPIC_FRECENCY_UPDATED "places-frecency-updated"
55 class mozIAnnotationService;
56 class nsNavHistory;
57 class QueryKeyValuePair;
58 class nsIEffectiveTLDService;
59 class nsIIDNService;
60 class PlacesSQLQueryBuilder;
61 class nsIAutoCompleteController;
63 // nsNavHistory
65 class nsNavHistory MOZ_FINAL : public nsSupportsWeakReference
66 , public nsINavHistoryService
67 , public nsIObserver
68 , public nsIBrowserHistory
69 , public nsPIPlacesDatabase
70 , public nsPIPlacesHistoryListenersNotifier
71 , public mozIStorageVacuumParticipant
72 {
73 friend class PlacesSQLQueryBuilder;
75 public:
76 nsNavHistory();
78 NS_DECL_THREADSAFE_ISUPPORTS
79 NS_DECL_NSINAVHISTORYSERVICE
80 NS_DECL_NSIBROWSERHISTORY
81 NS_DECL_NSIOBSERVER
82 NS_DECL_NSPIPLACESDATABASE
83 NS_DECL_NSPIPLACESHISTORYLISTENERSNOTIFIER
84 NS_DECL_MOZISTORAGEVACUUMPARTICIPANT
86 /**
87 * Obtains the nsNavHistory object.
88 */
89 static already_AddRefed<nsNavHistory> GetSingleton();
91 /**
92 * Initializes the nsNavHistory object. This should only be called once.
93 */
94 nsresult Init();
96 /**
97 * Used by other components in the places directory such as the annotation
98 * service to get a reference to this history object. Returns a pointer to
99 * the service if it exists. Otherwise creates one. Returns nullptr on error.
100 */
101 static nsNavHistory* GetHistoryService()
102 {
103 if (!gHistoryService) {
104 nsCOMPtr<nsINavHistoryService> serv =
105 do_GetService(NS_NAVHISTORYSERVICE_CONTRACTID);
106 NS_ENSURE_TRUE(serv, nullptr);
107 NS_ASSERTION(gHistoryService, "Should have static instance pointer now");
108 }
109 return gHistoryService;
110 }
112 /**
113 * Used by other components in the places directory to get a reference to a
114 * const version of this history object.
115 *
116 * @return A pointer to a const version of the service if it exists,
117 * nullptr otherwise.
118 */
119 static const nsNavHistory* GetConstHistoryService()
120 {
121 const nsNavHistory* const history = gHistoryService;
122 return history;
123 }
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,
139 int64_t* _pageId, nsCString& _GUID);
141 /**
142 * Fetches the database id and the GUID associated to the given URI, creating
143 * a new database entry if one doesn't exist yet.
144 *
145 * @param aURI
146 * The page to look for or create.
147 * @param _pageId
148 * Will be set to the database id associated with the page.
149 * @param _GUID
150 * Will be set to the unique id associated with the page.
151 * @note This DOES NOT check for bad URLs other than that they're nonempty.
152 * @note This DOES NOT update frecency of the page.
153 */
154 nsresult GetOrCreateIdForPage(nsIURI* aURI,
155 int64_t* _pageId, nsCString& _GUID);
157 /**
158 * Asynchronously recalculates frecency for a given page.
159 *
160 * @param aPlaceId
161 * Place id to recalculate the frecency for.
162 * @note If the new frecency is a non-zero value it will also unhide the page,
163 * otherwise will reuse the old hidden value.
164 */
165 nsresult UpdateFrecency(int64_t aPlaceId);
167 /**
168 * Recalculates frecency for all pages requesting that (frecency < 0). Those
169 * may be generated:
170 * * After a "clear private data"
171 * * After removing visits
172 * * After migrating from older versions
173 */
174 nsresult FixInvalidFrecencies();
176 /**
177 * Invalidate the frecencies of a list of places, so they will be recalculated
178 * at the first idle-daily notification.
179 *
180 * @param aPlacesIdsQueryString
181 * Query string containing list of places to be invalidated. If it's
182 * an empty string all places will be invalidated.
183 */
184 nsresult invalidateFrecencies(const nsCString& aPlaceIdsQueryString);
186 /**
187 * These functions return non-owning references to the locale-specific
188 * objects for places components.
189 */
190 nsIStringBundle* GetBundle();
191 nsIStringBundle* GetDateFormatBundle();
192 nsICollation* GetCollation();
193 void GetStringFromName(const char16_t* aName, nsACString& aResult);
194 void GetAgeInDaysString(int32_t aInt, const char16_t *aName,
195 nsACString& aResult);
196 void GetMonthName(int32_t aIndex, nsACString& aResult);
197 void GetMonthYear(int32_t aMonth, int32_t aYear, nsACString& aResult);
199 // Returns whether history is enabled or not.
200 bool IsHistoryDisabled() {
201 return !mHistoryEnabled;
202 }
204 // Constants for the columns returned by the above statement.
205 static const int32_t kGetInfoIndex_PageID;
206 static const int32_t kGetInfoIndex_URL;
207 static const int32_t kGetInfoIndex_Title;
208 static const int32_t kGetInfoIndex_RevHost;
209 static const int32_t kGetInfoIndex_VisitCount;
210 static const int32_t kGetInfoIndex_VisitDate;
211 static const int32_t kGetInfoIndex_FaviconURL;
212 static const int32_t kGetInfoIndex_ItemId;
213 static const int32_t kGetInfoIndex_ItemDateAdded;
214 static const int32_t kGetInfoIndex_ItemLastModified;
215 static const int32_t kGetInfoIndex_ItemParentId;
216 static const int32_t kGetInfoIndex_ItemTags;
217 static const int32_t kGetInfoIndex_Frecency;
218 static const int32_t kGetInfoIndex_Hidden;
219 static const int32_t kGetInfoIndex_Guid;
221 int64_t GetTagsFolder();
223 // this actually executes a query and gives you results, it is used by
224 // nsNavHistoryQueryResultNode
225 nsresult GetQueryResults(nsNavHistoryQueryResultNode *aResultNode,
226 const nsCOMArray<nsNavHistoryQuery>& aQueries,
227 nsNavHistoryQueryOptions *aOptions,
228 nsCOMArray<nsNavHistoryResultNode>* aResults);
230 // Take a row of kGetInfoIndex_* columns and construct a ResultNode.
231 // The row must contain the full set of columns.
232 nsresult RowToResult(mozIStorageValueArray* aRow,
233 nsNavHistoryQueryOptions* aOptions,
234 nsNavHistoryResultNode** aResult);
235 nsresult QueryRowToResult(int64_t aItemId, const nsACString& aURI,
236 const nsACString& aTitle,
237 uint32_t aAccessCount, PRTime aTime,
238 const nsACString& aFavicon,
239 nsNavHistoryResultNode** aNode);
241 nsresult VisitIdToResultNode(int64_t visitId,
242 nsNavHistoryQueryOptions* aOptions,
243 nsNavHistoryResultNode** aResult);
245 nsresult BookmarkIdToResultNode(int64_t aBookmarkId,
246 nsNavHistoryQueryOptions* aOptions,
247 nsNavHistoryResultNode** aResult);
248 nsresult URIToResultNode(nsIURI* aURI,
249 nsNavHistoryQueryOptions* aOptions,
250 nsNavHistoryResultNode** aResult);
252 // used by other places components to send history notifications (for example,
253 // when the favicon has changed)
254 void SendPageChangedNotification(nsIURI* aURI, uint32_t aChangedAttribute,
255 const nsAString& aValue,
256 const nsACString& aGUID);
258 /**
259 * Returns current number of days stored in history.
260 */
261 int32_t GetDaysOfHistory();
263 // used by query result nodes to update: see comment on body of CanLiveUpdateQuery
264 static uint32_t GetUpdateRequirements(const nsCOMArray<nsNavHistoryQuery>& aQueries,
265 nsNavHistoryQueryOptions* aOptions,
266 bool* aHasSearchTerms);
267 bool EvaluateQueryForNode(const nsCOMArray<nsNavHistoryQuery>& aQueries,
268 nsNavHistoryQueryOptions* aOptions,
269 nsNavHistoryResultNode* aNode);
271 static nsresult AsciiHostNameFromHostString(const nsACString& aHostName,
272 nsACString& aAscii);
273 void DomainNameFromURI(nsIURI* aURI,
274 nsACString& aDomainName);
275 static PRTime NormalizeTime(uint32_t aRelative, PRTime aOffset);
277 // Don't use these directly, inside nsNavHistory use UpdateBatchScoper,
278 // else use nsINavHistoryService::RunInBatchMode
279 nsresult BeginUpdateBatch();
280 nsresult EndUpdateBatch();
282 // The level of batches' nesting, 0 when no batches are open.
283 int32_t mBatchLevel;
284 // Current active transaction for a batch.
285 mozStorageTransaction* mBatchDBTransaction;
287 // better alternative to QueryStringToQueries (in nsNavHistoryQuery.cpp)
288 nsresult QueryStringToQueryArray(const nsACString& aQueryString,
289 nsCOMArray<nsNavHistoryQuery>* aQueries,
290 nsNavHistoryQueryOptions** aOptions);
292 typedef nsDataHashtable<nsCStringHashKey, nsCString> StringHash;
294 /**
295 * Indicates if it is OK to notify history observers or not.
296 *
297 * @return true if it is OK to notify, false otherwise.
298 */
299 bool canNotify() { return mCanNotify; }
301 enum RecentEventFlags {
302 RECENT_TYPED = 1 << 0, // User typed in URL recently
303 RECENT_ACTIVATED = 1 << 1, // User tapped URL link recently
304 RECENT_BOOKMARKED = 1 << 2 // User bookmarked URL recently
305 };
307 /**
308 * Returns any recent activity done with a URL.
309 * @return Any recent events associated with this URI. Each bit is set
310 * according to RecentEventFlags enum values.
311 */
312 uint32_t GetRecentFlags(nsIURI *aURI);
314 /**
315 * Registers a TRANSITION_EMBED visit for the session.
316 *
317 * @param aURI
318 * URI of the page.
319 * @param aTime
320 * Visit time. Only the last registered visit time is retained.
321 */
322 void registerEmbedVisit(nsIURI* aURI, int64_t aTime);
324 /**
325 * Returns whether the specified url has a embed visit.
326 *
327 * @param aURI
328 * URI of the page.
329 * @return whether the page has a embed visit.
330 */
331 bool hasEmbedVisit(nsIURI* aURI);
333 /**
334 * Clears all registered embed visits.
335 */
336 void clearEmbedVisits();
338 int32_t GetFrecencyAgedWeight(int32_t aAgeInDays) const
339 {
340 if (aAgeInDays <= mFirstBucketCutoffInDays) {
341 return mFirstBucketWeight;
342 }
343 if (aAgeInDays <= mSecondBucketCutoffInDays) {
344 return mSecondBucketWeight;
345 }
346 if (aAgeInDays <= mThirdBucketCutoffInDays) {
347 return mThirdBucketWeight;
348 }
349 if (aAgeInDays <= mFourthBucketCutoffInDays) {
350 return mFourthBucketWeight;
351 }
352 return mDefaultWeight;
353 }
355 int32_t GetFrecencyBucketWeight(int32_t aBucketIndex) const
356 {
357 switch(aBucketIndex) {
358 case 1:
359 return mFirstBucketWeight;
360 case 2:
361 return mSecondBucketWeight;
362 case 3:
363 return mThirdBucketWeight;
364 case 4:
365 return mFourthBucketWeight;
366 default:
367 return mDefaultWeight;
368 }
369 }
371 int32_t GetFrecencyTransitionBonus(int32_t aTransitionType,
372 bool aVisited) const
373 {
374 switch (aTransitionType) {
375 case nsINavHistoryService::TRANSITION_EMBED:
376 return mEmbedVisitBonus;
377 case nsINavHistoryService::TRANSITION_FRAMED_LINK:
378 return mFramedLinkVisitBonus;
379 case nsINavHistoryService::TRANSITION_LINK:
380 return mLinkVisitBonus;
381 case nsINavHistoryService::TRANSITION_TYPED:
382 return aVisited ? mTypedVisitBonus : mUnvisitedTypedBonus;
383 case nsINavHistoryService::TRANSITION_BOOKMARK:
384 return aVisited ? mBookmarkVisitBonus : mUnvisitedBookmarkBonus;
385 case nsINavHistoryService::TRANSITION_DOWNLOAD:
386 return mDownloadVisitBonus;
387 case nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT:
388 return mPermRedirectVisitBonus;
389 case nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY:
390 return mTempRedirectVisitBonus;
391 default:
392 // 0 == undefined (see bug #375777 for details)
393 NS_WARN_IF_FALSE(!aTransitionType, "new transition but no bonus for frecency");
394 return mDefaultVisitBonus;
395 }
396 }
398 int32_t GetNumVisitsForFrecency() const
399 {
400 return mNumVisitsForFrecency;
401 }
403 /**
404 * Fires onVisit event to nsINavHistoryService observers
405 */
406 void NotifyOnVisit(nsIURI* aURI,
407 int64_t aVisitID,
408 PRTime aTime,
409 int64_t referringVisitID,
410 int32_t aTransitionType,
411 const nsACString& aGUID,
412 bool aHidden);
414 /**
415 * Fires onTitleChanged event to nsINavHistoryService observers
416 */
417 void NotifyTitleChange(nsIURI* aURI,
418 const nsString& title,
419 const nsACString& aGUID);
421 /**
422 * Fires onFrecencyChanged event to nsINavHistoryService observers
423 */
424 void NotifyFrecencyChanged(nsIURI* aURI,
425 int32_t aNewFrecency,
426 const nsACString& aGUID,
427 bool aHidden,
428 PRTime aLastVisitDate);
430 /**
431 * Fires onManyFrecenciesChanged event to nsINavHistoryService observers
432 */
433 void NotifyManyFrecenciesChanged();
435 /**
436 * Posts a runnable to the main thread that calls NotifyFrecencyChanged.
437 */
438 void DispatchFrecencyChangedNotification(const nsACString& aSpec,
439 int32_t aNewFrecency,
440 const nsACString& aGUID,
441 bool aHidden,
442 PRTime aLastVisitDate) const;
444 bool isBatching() {
445 return mBatchLevel > 0;
446 }
448 private:
449 ~nsNavHistory();
451 // used by GetHistoryService
452 static nsNavHistory *gHistoryService;
454 protected:
456 // Database handle.
457 nsRefPtr<mozilla::places::Database> mDB;
459 /**
460 * Decays frecency and inputhistory values. Runs on idle-daily.
461 */
462 nsresult DecayFrecency();
464 nsresult CalculateFrecency(int64_t aPageID, int32_t aTyped, int32_t aVisitCount, nsAutoCString &aURL, int32_t *aFrecency);
465 nsresult CalculateFrecencyInternal(int64_t aPageID, int32_t aTyped, int32_t aVisitCount, bool aIsBookmarked, int32_t *aFrecency);
467 nsresult RemovePagesInternal(const nsCString& aPlaceIdsQueryString);
468 nsresult CleanupPlacesOnVisitsDelete(const nsCString& aPlaceIdsQueryString);
470 /**
471 * Loads all of the preferences that we use into member variables.
472 *
473 * @note If mPrefBranch is nullptr, this does nothing.
474 */
475 void LoadPrefs();
477 /**
478 * Calculates and returns value for mCachedNow.
479 * This is an hack to avoid calling PR_Now() too often, as is the case when
480 * we're asked the ageindays of many history entries in a row. A timer is
481 * set which will clear our valid flag after a short timeout.
482 */
483 PRTime GetNow();
484 PRTime mCachedNow;
485 nsCOMPtr<nsITimer> mExpireNowTimer;
486 /**
487 * Called when the cached now value is expired and needs renewal.
488 */
489 static void expireNowTimerCallback(nsITimer* aTimer, void* aClosure);
491 nsresult ConstructQueryString(const nsCOMArray<nsNavHistoryQuery>& aQueries,
492 nsNavHistoryQueryOptions* aOptions,
493 nsCString& queryString,
494 bool& aParamsPresent,
495 StringHash& aAddParams);
497 nsresult QueryToSelectClause(nsNavHistoryQuery* aQuery,
498 nsNavHistoryQueryOptions* aOptions,
499 int32_t aQueryIndex,
500 nsCString* aClause);
501 nsresult BindQueryClauseParameters(mozIStorageBaseStatement* statement,
502 int32_t aQueryIndex,
503 nsNavHistoryQuery* aQuery,
504 nsNavHistoryQueryOptions* aOptions);
506 nsresult ResultsAsList(mozIStorageStatement* statement,
507 nsNavHistoryQueryOptions* aOptions,
508 nsCOMArray<nsNavHistoryResultNode>* aResults);
510 void TitleForDomain(const nsCString& domain, nsACString& aTitle);
512 nsresult FilterResultSet(nsNavHistoryQueryResultNode *aParentNode,
513 const nsCOMArray<nsNavHistoryResultNode>& aSet,
514 nsCOMArray<nsNavHistoryResultNode>* aFiltered,
515 const nsCOMArray<nsNavHistoryQuery>& aQueries,
516 nsNavHistoryQueryOptions* aOptions);
518 // observers
519 nsMaybeWeakPtrArray<nsINavHistoryObserver> mObservers;
521 // effective tld service
522 nsCOMPtr<nsIEffectiveTLDService> mTLDService;
523 nsCOMPtr<nsIIDNService> mIDNService;
525 // localization
526 nsCOMPtr<nsIStringBundle> mBundle;
527 nsCOMPtr<nsIStringBundle> mDateFormatBundle;
528 nsCOMPtr<nsICollation> mCollation;
530 // recent events
531 typedef nsDataHashtable<nsCStringHashKey, int64_t> RecentEventHash;
532 RecentEventHash mRecentTyped;
533 RecentEventHash mRecentLink;
534 RecentEventHash mRecentBookmark;
536 // Embed visits tracking.
537 class VisitHashKey : public nsURIHashKey
538 {
539 public:
540 VisitHashKey(const nsIURI* aURI)
541 : nsURIHashKey(aURI)
542 {
543 }
544 VisitHashKey(const VisitHashKey& aOther)
545 : nsURIHashKey(aOther)
546 {
547 NS_NOTREACHED("Do not call me!");
548 }
549 PRTime visitTime;
550 };
552 nsTHashtable<VisitHashKey> mEmbedVisits;
554 bool CheckIsRecentEvent(RecentEventHash* hashTable,
555 const nsACString& url);
556 void ExpireNonrecentEvents(RecentEventHash* hashTable);
558 #ifdef MOZ_XUL
559 nsresult AutoCompleteFeedback(int32_t aIndex,
560 nsIAutoCompleteController *aController);
561 #endif
563 // Whether history is enabled or not.
564 // Will mimic value of the places.history.enabled preference.
565 bool mHistoryEnabled;
567 // Frecency preferences.
568 int32_t mNumVisitsForFrecency;
569 int32_t mFirstBucketCutoffInDays;
570 int32_t mSecondBucketCutoffInDays;
571 int32_t mThirdBucketCutoffInDays;
572 int32_t mFourthBucketCutoffInDays;
573 int32_t mFirstBucketWeight;
574 int32_t mSecondBucketWeight;
575 int32_t mThirdBucketWeight;
576 int32_t mFourthBucketWeight;
577 int32_t mDefaultWeight;
578 int32_t mEmbedVisitBonus;
579 int32_t mFramedLinkVisitBonus;
580 int32_t mLinkVisitBonus;
581 int32_t mTypedVisitBonus;
582 int32_t mBookmarkVisitBonus;
583 int32_t mDownloadVisitBonus;
584 int32_t mPermRedirectVisitBonus;
585 int32_t mTempRedirectVisitBonus;
586 int32_t mDefaultVisitBonus;
587 int32_t mUnvisitedBookmarkBonus;
588 int32_t mUnvisitedTypedBonus;
590 // in nsNavHistoryQuery.cpp
591 nsresult TokensToQueries(const nsTArray<QueryKeyValuePair>& aTokens,
592 nsCOMArray<nsNavHistoryQuery>* aQueries,
593 nsNavHistoryQueryOptions* aOptions);
595 int64_t mTagsFolder;
597 int32_t mDaysOfHistory;
598 int64_t mLastCachedStartOfDay;
599 int64_t mLastCachedEndOfDay;
601 // Used to enable and disable the observer notifications
602 bool mCanNotify;
603 nsCategoryCache<nsINavHistoryObserver> mCacheObservers;
604 };
607 #define PLACES_URI_PREFIX "place:"
609 /* Returns true if the given URI represents a history query. */
610 inline bool IsQueryURI(const nsCString &uri)
611 {
612 return StringBeginsWith(uri, NS_LITERAL_CSTRING(PLACES_URI_PREFIX));
613 }
615 /* Extracts the query string from a query URI. */
616 inline const nsDependentCSubstring QueryURIToQuery(const nsCString &uri)
617 {
618 NS_ASSERTION(IsQueryURI(uri), "should only be called for query URIs");
619 return Substring(uri, NS_LITERAL_CSTRING(PLACES_URI_PREFIX).Length());
620 }
622 #endif // nsNavHistory_h_