Using the Places history service

Please see History Service Design for information on the design of the history service, and The Places database for a higher-level design overview of Places. This page provides a map to the external API.

History services interface overview

The Mozilla history service has undergone many revisions. To maintain backwards compatibility, each version has implemented the older interfaces, resulting in functionality spread across many interfaces. The places history service ("NavHistory") implements these history interfaces:

  • nsIGlobalHistory2: Basic add page, is visited functionality used by the docshell when visiting and rendering pages.
  • nsIGlobalHistory3: Adds extra functions for dealing with redirects and hints for rendering (gecko flags).
  • nsIBrowserHistory: Adds functions used by the basic browser like marking pages as typed in the URL bar, and removing pages as from the history interface.
  • nsINavHistoryService: Complex query functions, more fine-grained getters and setters.
  • nsIAutoCompleteSearch: URL-bar autocomplete from history
From 1.9.1 (Firefox3.1) on, don't use any Places service on (or after) quit-application has been notified, since the database connection will be closed to allow the last sync, and changes will most likely be lost. Use quit-application-granted instead.

Differences from previous implementations

The previous nsGlobalHistory service stored one entry for each page in history. This entry contained the URL, title, visit count, last visit date, first visit date, host name, last referrer, flags for typed, hidden, and gecko flags (gecko flags is trunk only).

The NavHistory service has broken this into two tables (see History Service Design). The main URL table stores the information about the page: URL, host name, title, visit count, hidden, and typed. Stored separately is the information specific to each visit. This information is called a "visit" in this document and in the code. A visit contains a reference to the URL table for the page, the visit date, the transition type (typed, click, redirect, bookmark, etc.), a reference to the referring visit, and the session ID.

This separation of the global page information and the visit allows us to store information about each time the page was visited instead of just the last time. Using the referrer information in each visit, the browsing path can be reconstructed at any time.

The "session ID" allows these paths to be reconstructed more easily. When the user starts browsing (for example, by typing in a link or following a bookmark), a new session ID is created. New visits get the same session ID as their referrer. This means that one "session" is comprised of going to a new page, and following a bunch of links or redirects. A session is ended when a new URL is typed in or selected from bookmarks. These session IDs allow the dotted lines separating related pages in the history view to be easily computed.

Creating the history service

The Places history service's contract ID is "@mozilla.org/browser/nav-history-service;1":

var historyService = Components.classes["@mozilla.org/browser/nav-history-service;1"]
                               .getService(Components.interfaces.nsINavHistoryService);

It also responds to the old contract ID for URl bar autocomplete "@mozilla.org/autocomplete/search;1?name=history" and the contract ID for the old history system (since it is backwards-compatible) "@mozilla.org/browser/global-history;2".

If database initialization completes correctly a "places-init-complete" topic is notified, at this point is possible to look for database status:

var databaseStatus = historyService.databaseStatus;
switch (databaseStatus) {
  case historyService.DATABASE_STATUS_OK:
    // Database did already exist and has been correctly initialized.
    break;
  case historyService.DATABASE_STATUS_CREATE:
    // Database did not exist, a new one has just been created and initialized.
    break;
  case historyService.DATABASE_STATUS_CORRUPT:
    // Database was corrupt, has been moved to a .corrupt file and a new one has been created and initialized.
    break;
  case historyService.DATABASE_STATUS_UPGRADED:
    // Database had an old schema version and has been upgraded to a new one.
    break;
}

In case the database is locked by a third party process and cannot be opened, a "places-database-locked" notification is fired, in such a case the service won't be able to initialize.

Adding pages to history

nsIGlobalHistory2.addURI: This is the basic function for adding pages to history that is called by the docshell as you browse. The redirect flag is deprecated. See addDocumentRedirect below.

nsIGlobalHistory3.addDocumentRedirect: This is called by the docshell when a redirect occurs. It replaces the old redirect flag on addURI. It gives the old and new channels to the history service so that the source page of the redirect can be determined.

nsIBrowserHistory.addPageWithDetails: Called by history importing code. New code should use nsINavHistoryService.setPageDetails.

nsINavHistoryService.addVisit: This is an advanced function that allows the caller to set the exact referring visit, the time, the session, etc. It is designed for people writing synchronizing or backup services that need access to all the flags. Under normal browsing, addURI and addDocumentRedirect will infer this information for you.

Modifying pages in history

nsIGlobalHistory2.setPageTitle: Called by Gecko when the <title> element is encountered.

nsIGlobalHistory3.setGeckoFlags: Called by Gecko to store rendering information about a page. Currently, this is used to store whether there was a scrollbar, which allows more efficient layout if the page is revisited. However, this is not yet supported by the NavHistory implementation.

nsIBrowserHistory.removePage: Removes a given URI and all of its visits from the history database. This is called by the UI when the user deletes a history entry.

nsIBrowserHistory.removePagesFromHost: Called from the UI when the user deletes a group associated with a host or domain. This function allows you to delete pages from a specific host, or pages from all hosts in a given domain.

nsIBrowserHistory.hidePage: Hides a page so that it does not appear in the UI. Many pages are not visible in normal history lists, such as redirects and sub-frame contents.This is not implemented in NavHistory.

nsIBrowserHistory.markPageAsTyped: Called by the URL bar when the user types in a URL. This can be and is calledbefore the page is actually added to history, since the page isn't added until it actually starts loading. The typed flag affects the URL bar autocomplete. This will cause the transition type of the next visit of the URL to be marked as "typed."

nsINavHistoryService.markPageAsFollowedBookmark: Called by the UI (implemented, but not yet called, see bug 409301) when the user selects a bookmark. This will cause the transition type of the next visit of the URL to be marked as "bookmark."

nsINavHistoryService.setPageUserTitle: Sets the user-defined title for the page, which will override the actual page title when displayed in the UI. This is used for bookmark titles.This function may be removed if the bookmark service is changed.

nsINavHistoryService.setPageDetails: Used to set all of the global bits associated with a URL. It is designed for synchronizing or backup services.

Basic querying of the history system

nsIGlobalHistory2.isVisited: Called by Gecko when rendering links. When isVisited returns true, the link gets the "visited" style. Otherwise, the link is colored as unvisited.

nsIGlobalHistory3.getGeckoFlags: Retrieves information previously set using setGeckoFlags. It is not yet implemented in the Places history system.

nsIBrowserHistory.lastPageVisited: Contains the URI of the last page visited. This is used when the preference is set that causes the last page in new windows.

nsIBrowserHistory.count: The number of pages in history. This is used by the "clear history" button to determine if there are any pages in history. Because actually counting all the pages in history is expensive,NavHistory will always return the value 0 or 1. 0 is returned when there is no history, 1 is returned when there are one or more pages in history.Deprecated, use hasHistoryEntries instead.

nsINavHistoryService.hasHistoryEntries: Exactly the same as nsIBrowserHistory.count, except with a better name and actually returning a boolean. Preferred over "count".

nsINavHistory.canAddURI: Determines whether the given URI will be stored by the history system. Many types of URIs, such as "chrome:" URIs, are not stored when addURI is called. This function allows you to determine whether it will be or not.

Advanced querying

See Querying Places for more detailed examples on how to used the advanced querying functionality of NavHistory.

nsINavHistoryService.getNewQuery: Returns a new query object initialized to the default values. You can pass this to executeQueries().

nsINavHistoryService.getNewQueryOptions: Returns a new query options object initialized to the default values. You can pass this to executeQueries().

nsINavHistoryService.executeQuery: Runs a query with a single query object and options. All the parameters set on the query object will be ANDed together.

nsINavHistoryService.executeQueries: Runs multiple query objects as a query. The parameters within on query as ANDed together as in executeQuery(), then the results of the different queries in the array are ORed together.

nsINavHistoryService.queriesToQueryString: Returns a serialized version of the queries as a "place:" URI. You should not count on this format, always use this function instead of hard-coding your own query strings.

nsINavHistoryService.queryStringToQueries: Converts a serialized query ("place:" URI) back to the actual query objects and options.

Miscellaneous

nsINavHistoryService.addObserver: Adds a history observer, which will be notified of changes to the history system.

nsINavHistoryService.removeObserver: Removes a previously added observer.

nsINavHistoryService.beginUpdateBatch: Call when you will be making many small changes to the history system. Observers generally stop updating UI when they are inside a batch, potentially making the operations faster. If you are just doing a few changes, it is probably better to not use a batch since incremental updates are not done. Be sure to call endUpdateBatch when you are done or the UI will be permanently broken.

nsINavHistoryService.endUpdateBatch: Ends a batch operation previously started with beginUpdateBatch.

See also