Merge with mc

This commit is contained in:
Doug Turner 2010-06-29 20:10:23 -07:00
commit a73902aba6
16 changed files with 143 additions and 1700 deletions

View File

@ -43,7 +43,6 @@
#include "nsISupports.h"
class nsIURI;
class nsString;
namespace mozilla {
@ -52,7 +51,7 @@ namespace mozilla {
}
#define IHISTORY_IID \
{0x6f736049, 0x6370, 0x4376, {0xb7, 0x17, 0xfa, 0xfc, 0x0b, 0x4f, 0xd0, 0xf1}}
{0xaf27265d, 0x5672, 0x4d23, {0xa0, 0x75, 0x34, 0x8e, 0xb9, 0x73, 0x5a, 0x9a}}
class IHistory : public nsISupports
{
@ -97,50 +96,6 @@ public:
*/
NS_IMETHOD UnregisterVisitedCallback(nsIURI *aURI, dom::Link *aLink) = 0;
enum VisitFlags {
/**
* Indicates whether the URI was loaded in a top-level window.
*/
TOP_LEVEL = 1 << 0,
/**
* Indicates whether the URI was loaded as part of a permanent redirect.
*/
REDIRECT_PERMANENT = 1 << 1,
/**
* Indicates whether the URI was loaded as part of a temporary redirect.
*/
REDIRECT_TEMPORARY = 1 << 2
};
/**
* Adds a history visit for the URI.
*
* @pre aURI must not be null.
*
* @param aURI
* The URI of the page being visited.
* @param aLastVisitedURI
* The URI of the last visit in the chain.
* @param aFlags
* The VisitFlags describing this visit.
*/
NS_IMETHOD VisitURI(
nsIURI *aURI,
nsIURI *aLastVisitedURI,
PRUint32 aFlags
) = 0;
/**
* Set the title of the URI.
*
* @pre aURI must not be null.
*
* @param aURI
* The URI to set the title for.
* @param aTitle
* The title string.
*/
NS_IMETHOD SetURITitle(nsIURI* aURI, const nsAString& aTitle) = 0;
};
NS_DEFINE_STATIC_IID_ACCESSOR(IHistory, IHISTORY_IID)
@ -149,11 +104,7 @@ NS_DEFINE_STATIC_IID_ACCESSOR(IHistory, IHISTORY_IID)
NS_IMETHOD RegisterVisitedCallback(nsIURI *aURI, \
mozilla::dom::Link *aContent); \
NS_IMETHOD UnregisterVisitedCallback(nsIURI *aURI, \
mozilla::dom::Link *aContent); \
NS_IMETHOD VisitURI(nsIURI *aURI, \
nsIURI *aLastVisitedURI, \
PRUint32 aFlags); \
NS_IMETHOD SetURITitle(nsIURI* aURI, const nsAString& aTitle);
mozilla::dom::Link *aContent);
} // namespace mozilla

View File

@ -112,8 +112,6 @@
#include "nsIOfflineCacheUpdate.h"
#include "nsCPrefetchService.h"
#include "nsJSON.h"
#include "IHistory.h"
#include "mozilla/Services.h"
// we want to explore making the document own the load group
// so we can associate the document URI with the load group.
@ -4704,16 +4702,11 @@ nsDocShell::SetTitle(const PRUnichar * aTitle)
treeOwnerAsWin->SetTitle(aTitle);
}
if (mCurrentURI && mLoadType != LOAD_ERROR_PAGE) {
nsCOMPtr<IHistory> history = services::GetHistoryService();
if (history) {
history->SetURITitle(mCurrentURI, mTitle);
}
else if (mGlobalHistory) {
mGlobalHistory->SetPageTitle(mCurrentURI, nsString(mTitle));
}
if (mGlobalHistory && mCurrentURI && mLoadType != LOAD_ERROR_PAGE) {
mGlobalHistory->SetPageTitle(mCurrentURI, nsString(mTitle));
}
// Update SessionHistory with the document's title.
if (mOSHE && mLoadType != LOAD_BYPASS_HISTORY &&
mLoadType != LOAD_ERROR_PAGE) {
@ -5679,53 +5672,32 @@ nsDocShell::OnRedirectStateChange(nsIChannel* aOldChannel,
if (!(aStateFlags & STATE_IS_DOCUMENT))
return; // not a toplevel document
nsCOMPtr<nsIURI> oldURI, newURI;
aOldChannel->GetURI(getter_AddRefs(oldURI));
aNewChannel->GetURI(getter_AddRefs(newURI));
if (!oldURI || !newURI) {
return;
nsCOMPtr<nsIGlobalHistory3> history3(do_QueryInterface(mGlobalHistory));
nsresult result = NS_ERROR_NOT_IMPLEMENTED;
if (history3) {
// notify global history of this redirect
result = history3->AddDocumentRedirect(aOldChannel, aNewChannel,
aRedirectFlags, !IsFrame());
}
// Below a URI visit is saved (see AddURIVisit method doc).
// The visit chain looks something like:
// ...
// Site N - 1
// => Site N
// (redirect to =>) Site N + 1 (we are here!)
// Get N - 1 and transition type
nsCOMPtr<nsIURI> previousURI;
PRUint32 previousFlags = 0;
ExtractLastVisit(aOldChannel, getter_AddRefs(previousURI), &previousFlags);
if (aRedirectFlags & nsIChannelEventSink::REDIRECT_INTERNAL ||
ChannelIsPost(aOldChannel)) {
// 1. Internal redirects are ignored because they are specific to the
// channel implementation.
// 2. POSTs are not saved by global history.
//
// Regardless, we need to propagate the previous visit to the new
// channel.
SaveLastVisit(aNewChannel, previousURI, previousFlags);
}
else {
nsCOMPtr<nsIURI> referrer;
// Treat referrer as null if there is an error getting it.
(void)NS_GetReferrerFromChannel(aOldChannel,
getter_AddRefs(referrer));
// Add visit N -1 => N
AddURIVisit(oldURI, referrer, previousURI, previousFlags);
// Since N + 1 could be the final destination, we will not save N => N + 1
// here. OnNewURI will do that, so we will cache it.
SaveLastVisit(aNewChannel, oldURI, aRedirectFlags);
if (result == NS_ERROR_NOT_IMPLEMENTED) {
// when there is no GlobalHistory3, or it doesn't implement
// AddToplevelRedirect, we fall back to GlobalHistory2. Just notify
// that the redirecting page was a rePdirect so it will be link colored
// but not visible.
nsCOMPtr<nsIURI> oldURI;
aOldChannel->GetURI(getter_AddRefs(oldURI));
if (! oldURI)
return; // nothing to tell anybody about
AddToGlobalHistory(oldURI, PR_TRUE, aOldChannel);
}
// check if the new load should go through the application cache.
nsCOMPtr<nsIApplicationCacheChannel> appCacheChannel =
do_QueryInterface(aNewChannel);
if (appCacheChannel) {
nsCOMPtr<nsIURI> newURI;
aNewChannel->GetURI(getter_AddRefs(newURI));
appCacheChannel->SetChooseApplicationCache(ShouldCheckAppCache(newURI));
}
@ -8965,7 +8937,7 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner,
nsCOMPtr<nsIInputStream> inputStream;
if (aChannel) {
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
// Check if the HTTPChannel is hiding under a multiPartChannel
if (!httpChannel) {
GetHttpChannel(aChannel, getter_AddRefs(httpChannel));
@ -9055,8 +9027,8 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner,
nsCOMPtr<nsICachingChannel> cacheChannel(do_QueryInterface(aChannel));
nsCOMPtr<nsISupports> cacheKey;
// Get the Cache Key and store it in SH.
if (cacheChannel)
// Get the Cache Key and store it in SH.
if (cacheChannel)
cacheChannel->GetCacheKey(getter_AddRefs(cacheKey));
// If we already have a loading history entry, store the new cache key
// in it. Otherwise, since we're doing a reload and won't be updating
@ -9078,22 +9050,10 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner,
getter_AddRefs(mLSHE));
}
// Update Global history
if (aAddToGlobalHistory) {
// If this is a POST request, we do not want to include this in global
// history.
if (!ChannelIsPost(aChannel)) {
nsCOMPtr<nsIURI> previousURI;
PRUint32 previousFlags = 0;
ExtractLastVisit(aChannel, getter_AddRefs(previousURI),
&previousFlags);
nsCOMPtr<nsIURI> referrer;
// Treat referrer as null if there is an error getting it.
(void)NS_GetReferrerFromChannel(aChannel,
getter_AddRefs(referrer));
AddURIVisit(aURI, referrer, previousURI, previousFlags);
}
// Get the referrer uri from the channel
AddToGlobalHistory(aURI, PR_FALSE, aChannel);
}
}
@ -9412,7 +9372,7 @@ nsDocShell::AddState(nsIVariant *aData, const nsAString& aTitle,
SetCurrentURI(newURI, nsnull, PR_TRUE);
document->SetDocumentURI(newURI);
AddURIVisit(newURI, oldURI, oldURI, 0);
AddToGlobalHistory(newURI, PR_FALSE, oldURI);
}
else {
FireOnLocationChange(this, nsnull, mCurrentURI);
@ -10108,109 +10068,53 @@ NS_IMETHODIMP nsDocShell::MakeEditable(PRBool inWaitForUriLoad)
return mEditorData->MakeEditable(inWaitForUriLoad);
}
bool
nsDocShell::ChannelIsPost(nsIChannel* aChannel)
nsresult
nsDocShell::AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
nsIChannel * aChannel)
{
nsCOMPtr<nsIHttpChannel> httpChannel(do_QueryInterface(aChannel));
if (!httpChannel) {
return false;
// If this is a POST request, we do not want to include this in global
// history, so return early.
nsCOMPtr<nsIHttpChannel> hchan(do_QueryInterface(aChannel));
if (hchan) {
nsCAutoString type;
nsresult rv = hchan->GetRequestMethod(type);
if (NS_SUCCEEDED(rv) && type.EqualsLiteral("POST"))
return NS_OK;
}
nsCAutoString method;
httpChannel->GetRequestMethod(method);
return method.Equals("POST");
nsCOMPtr<nsIURI> referrer;
if (aChannel)
NS_GetReferrerFromChannel(aChannel, getter_AddRefs(referrer));
return AddToGlobalHistory(aURI, aRedirect, referrer);
}
void
nsDocShell::ExtractLastVisit(nsIChannel* aChannel,
nsIURI** aURI,
PRUint32* aChannelRedirectFlags)
nsresult
nsDocShell::AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
nsIURI * aReferrer)
{
nsCOMPtr<nsIPropertyBag2> props(do_QueryInterface(aChannel));
if (!props) {
return;
}
if (mItemType != typeContent || !mGlobalHistory)
return NS_OK;
nsresult rv = props->GetPropertyAsInterface(
NS_LITERAL_STRING("docshell.previousURI"),
NS_GET_IID(nsIURI),
reinterpret_cast<void**>(aURI)
);
PRBool visited;
nsresult rv = mGlobalHistory->IsVisited(aURI, &visited);
if (NS_FAILED(rv))
return rv;
if (NS_FAILED(rv)) {
// There is no last visit for this channel, so this must be the first
// link. Link the visit to the referrer of this request, if any.
// Treat referrer as null if there is an error getting it.
(void)NS_GetReferrerFromChannel(aChannel, aURI);
}
else {
rv = props->GetPropertyAsUint32(
NS_LITERAL_STRING("docshell.previousFlags"),
aChannelRedirectFlags
);
rv = mGlobalHistory->AddURI(aURI, aRedirect, !IsFrame(), aReferrer);
if (NS_FAILED(rv))
return rv;
NS_WARN_IF_FALSE(
NS_FAILED(rv),
"Could not fetch previous flags, URI will be treated like referrer"
);
}
}
void
nsDocShell::SaveLastVisit(nsIChannel* aChannel,
nsIURI* aURI,
PRUint32 aChannelRedirectFlags)
{
nsCOMPtr<nsIWritablePropertyBag2> props(do_QueryInterface(aChannel));
if (!props || !aURI) {
return;
}
props->SetPropertyAsInterface(NS_LITERAL_STRING("docshell.previousURI"),
aURI);
props->SetPropertyAsUint32(NS_LITERAL_STRING("docshell.previousFlags"),
aChannelRedirectFlags);
}
void
nsDocShell::AddURIVisit(nsIURI* aURI,
nsIURI* aReferrerURI,
nsIURI* aPreviousURI,
PRUint32 aChannelRedirectFlags)
{
NS_ASSERTION(aURI, "Visited URI is null!");
// Only content-type docshells save URI visits.
if (mItemType != typeContent) {
return;
}
nsCOMPtr<IHistory> history = services::GetHistoryService();
if (history) {
PRUint32 visitURIFlags = 0;
if (!IsFrame()) {
visitURIFlags |= IHistory::TOP_LEVEL;
if (!visited) {
nsCOMPtr<nsIObserverService> obsService =
mozilla::services::GetObserverService();
if (obsService) {
obsService->NotifyObservers(aURI, NS_LINK_VISITED_EVENT_TOPIC, nsnull);
}
if (aChannelRedirectFlags & nsIChannelEventSink::REDIRECT_TEMPORARY) {
visitURIFlags |= IHistory::REDIRECT_TEMPORARY;
}
else if (aChannelRedirectFlags &
nsIChannelEventSink::REDIRECT_PERMANENT) {
visitURIFlags |= IHistory::REDIRECT_PERMANENT;
}
(void)history->VisitURI(aURI, aPreviousURI, visitURIFlags);
}
else if (mGlobalHistory) {
// Falls back to sync global history interface.
(void)mGlobalHistory->AddURI(aURI,
!!aChannelRedirectFlags,
!IsFrame(),
aReferrerURI);
}
return NS_OK;
}
//*****************************************************************************

View File

@ -433,77 +433,12 @@ protected:
PRUint32 aRedirectFlags,
PRUint32 aStateFlags);
/**
* Helper function that determines if channel is an HTTP POST.
*
* @param aChannel
* The channel to test
*
* @return True iff channel is an HTTP post.
*/
bool ChannelIsPost(nsIChannel* aChannel);
// Global History
/**
* Helper function that finds the last URI and its transition flags for a
* channel.
*
* This method first checks the channel's property bag to see if previous
* info has been saved. If not, it gives back the referrer of the channel.
*
* @param aChannel
* The channel we are transitioning to
* @param aURI
* Output parameter with the previous URI, not addref'd
* @param aChannelRedirectFlags
* If a redirect, output parameter with the previous redirect flags
* from nsIChannelEventSink
*/
void ExtractLastVisit(nsIChannel* aChannel,
nsIURI** aURI,
PRUint32* aChannelRedirectFlags);
/**
* Helper function that caches a URI and a transition for saving later.
*
* @param aChannel
* Channel that will have these properties saved
* @param aURI
* The URI to save for later
* @param aChannelRedirectFlags
* The nsIChannelEventSink redirect flags to save for later
*/
void SaveLastVisit(nsIChannel* aChannel,
nsIURI* aURI,
PRUint32 aChannelRedirectFlags);
/**
* Helper function for adding a URI visit using IHistory. If IHistory is
* not available, the method tries nsIGlobalHistory2.
*
* The IHistory API maintains chains of visits, tracking both HTTP referrers
* and redirects for a user session. VisitURI requires the current URI and
* the previous URI in the chain.
*
* Visits can be saved either during a redirect or when the request has
* reached its final destination. The previous URI in the visit may be
* from another redirect or it may be the referrer.
*
* @pre aURI is not null.
*
* @param aURI
* The URI that was just visited
* @param aReferrerURI
* The referrer URI of this request
* @param aPreviousURI
* The previous URI of this visit (may be the same as aReferrerURI)
* @param aChannelRedirectFlags
* For redirects, the redirect flags from nsIChannelEventSink
* (0 otherwise)
*/
void AddURIVisit(nsIURI* aURI,
nsIURI* aReferrerURI,
nsIURI* aPreviousURI,
PRUint32 aChannelRedirectFlags);
nsresult AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
nsIChannel * aChannel);
nsresult AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
nsIURI * aReferrer);
// Helper Routines
nsresult ConfirmRepost(PRBool * aRepost);
@ -765,9 +700,6 @@ protected:
PRInt32 mMarginWidth;
PRInt32 mMarginHeight;
// This can either be a content docshell or a chrome docshell. After
// Create() is called, the type is not expected to change.
PRInt32 mItemType;
// Index into the SHTransaction list, indicating the previous and current

View File

@ -60,7 +60,7 @@ AsyncStatementCallback::HandleError(mozIStorageError *aError)
nsCAutoString warnMsg;
warnMsg.Append("An error occurred while executing an async statement: ");
warnMsg.AppendInt(result);
warnMsg.Append(result);
warnMsg.Append(" ");
warnMsg.Append(message);
NS_WARNING(warnMsg.get());
@ -180,33 +180,6 @@ URIBinder::Bind(mozIStorageBindingParams* aParams,
#undef URI_TO_URLCSTRING
nsresult
GetReversedHostname(nsIURI* aURI, nsString& aRevHost)
{
nsCAutoString forward8;
nsresult rv = aURI->GetHost(forward8);
NS_ENSURE_SUCCESS(rv, rv);
// can't do reversing in UTF8, better use 16-bit chars
GetReversedHostname(NS_ConvertUTF8toUTF16(forward8), aRevHost);
return NS_OK;
}
void
GetReversedHostname(const nsString& aForward, nsString& aRevHost)
{
ReverseString(aForward, aRevHost);
aRevHost.Append(PRUnichar('.'));
}
void
ReverseString(const nsString& aInput, nsString& aReversed)
{
aReversed.Truncate(0);
for (PRInt32 i = aInput.Length() - 1; i >= 0; i--) {
aReversed.Append(aInput[i]);
}
}
} // namespace places
} // namespace mozilla

View File

@ -136,44 +136,6 @@ public:
const nsACString& aURLString);
};
/**
* This extracts the hostname from the URI and reverses it in the
* form that we use (always ending with a "."). So
* "http://microsoft.com/" becomes "moc.tfosorcim."
*
* The idea behind this is that we can create an index over the items in
* the reversed host name column, and then query for as much or as little
* of the host name as we feel like.
*
* For example, the query "host >= 'gro.allizom.' AND host < 'gro.allizom/'
* Matches all host names ending in '.mozilla.org', including
* 'developer.mozilla.org' and just 'mozilla.org' (since we define all
* reversed host names to end in a period, even 'mozilla.org' matches).
* The important thing is that this operation uses the index. Any substring
* calls in a select statement (even if it's for the beginning of a string)
* will bypass any indices and will be slow).
*
* @param aURI
* URI that contains spec to reverse
* @param aRevHost
* Out parameter
*/
nsresult GetReversedHostname(nsIURI* aURI, nsString& aRevHost);
/**
* Similar method to GetReversedHostName but for strings
*/
void GetReversedHostname(const nsString& aForward, nsString& aRevHost);
/**
* Reverses a string.
*
* @param aInput
* The string to be reversed
* @param aReversed
* Ouput parameter will contain the reversed string
*/
void ReverseString(const nsString& aInput, nsString& aReversed);
} // namespace places
} // namespace mozilla

View File

@ -39,7 +39,6 @@
#include "History.h"
#include "nsNavHistory.h"
#include "nsNavBookmarks.h"
#include "Helpers.h"
#include "mozilla/storage.h"
@ -59,87 +58,6 @@ namespace places {
#define URI_VISITED "visited"
#define URI_NOT_VISITED "not visited"
#define URI_VISITED_RESOLUTION_TOPIC "visited-status-resolution"
// Observer event fired after a visit has been registered in the DB.
#define URI_VISIT_SAVED "uri-visit-saved"
////////////////////////////////////////////////////////////////////////////////
//// Step
class Step : public AsyncStatementCallback
{
public:
/**
* Executes statement asynchronously using this as a callback.
*
* @param aStmt
* Statement to execute asynchronously
*/
NS_IMETHOD ExecuteAsync(mozIStorageStatement* aStmt);
/**
* Called once after query is completed. If your query has more than one
* result set to process, you will want to override HandleResult to process
* each one.
*
* @param aResultSet
* Results from ExecuteAsync
* Unlike HandleResult, this *can be NULL* if there were no results.
*/
NS_IMETHOD Callback(mozIStorageResultSet* aResultSet);
/**
* By default, stores the last result set received in mResultSet.
* For queries with only one result set, you don't need to override.
*
* @param aResultSet
* Results from ExecuteAsync
*/
NS_IMETHOD HandleResult(mozIStorageResultSet* aResultSet);
/**
* By default, this calls Callback with any saved results from HandleResult.
* For queries with only one result set, you don't need to override.
*
* @param aReason
* SQL status code
*/
NS_IMETHOD HandleCompletion(PRUint16 aReason);
private:
// Used by HandleResult to cache results until HandleCompletion is called.
nsCOMPtr<mozIStorageResultSet> mResultSet;
};
NS_IMETHODIMP
Step::ExecuteAsync(mozIStorageStatement* aStmt)
{
nsCOMPtr<mozIStoragePendingStatement> handle;
nsresult rv = aStmt->ExecuteAsync(this, getter_AddRefs(handle));
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
NS_IMETHODIMP
Step::Callback(mozIStorageResultSet* aResultSet)
{
return NS_OK;
}
NS_IMETHODIMP
Step::HandleResult(mozIStorageResultSet* aResultSet)
{
mResultSet = aResultSet;
return NS_OK;
}
NS_IMETHODIMP
Step::HandleCompletion(PRUint16 aReason)
{
nsCOMPtr<mozIStorageResultSet> resultSet = mResultSet;
mResultSet = NULL;
Callback(resultSet);
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
//// Anonymous Helpers
@ -153,7 +71,7 @@ public:
static nsresult Start(nsIURI* aURI)
{
NS_PRECONDITION(aURI, "Null URI");
NS_ASSERTION(aURI, "Don't pass a null URI!");
nsNavHistory* navHist = nsNavHistory::GetHistoryService();
NS_ENSURE_TRUE(navHist, NS_ERROR_FAILURE);
@ -226,626 +144,6 @@ NS_IMPL_ISUPPORTS1(
mozIStorageStatementCallback
)
/**
* Fail-safe mechanism for ensuring that your task completes, no matter what.
* Pass this around as an nsAutoPtr in your steps to guarantee that when all
* your steps are finished, your task is finished.
*/
class FailSafeFinishTask
{
public:
~FailSafeFinishTask() {
History::GetService()->CurrentTaskFinished();
}
};
////////////////////////////////////////////////////////////////////////////////
//// Steps for VisitURI
struct VisitURIData : public FailSafeFinishTask
{
PRInt64 placeId;
PRInt32 hidden;
PRInt32 typed;
nsCOMPtr<nsIURI> uri;
// Url of last added visit in chain.
nsCString lastSpec;
PRInt64 lastVisitId;
PRInt32 transitionType;
PRInt64 sessionId;
PRTime dateTime;
};
/**
* Step 6: Update frecency of URI and notify observers.
*/
class UpdateFrecencyAndNotifyStep : public Step
{
public:
NS_DECL_ISUPPORTS
UpdateFrecencyAndNotifyStep(nsAutoPtr<VisitURIData> aData)
: mData(aData)
{
}
NS_IMETHOD Callback(mozIStorageResultSet* aResultSet)
{
// Result set contains new visit created in earlier step
NS_ENSURE_STATE(aResultSet);
nsCOMPtr<mozIStorageRow> row;
nsresult rv = aResultSet->GetNextRow(getter_AddRefs(row));
NS_ENSURE_SUCCESS(rv, rv);
PRInt64 visitId;
rv = row->GetInt64(0, &visitId);
NS_ENSURE_SUCCESS(rv, rv);
// TODO need to figure out story for not synchronous frecency updating
// (bug 556631)
// Swallow errors here, since if we've gotten this far, it's more
// important to notify the observers below.
nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_WARN_IF_FALSE(history, "Could not get history service");
nsNavBookmarks* bookmarks = nsNavBookmarks::GetBookmarksService();
NS_WARN_IF_FALSE(bookmarks, "Could not get bookmarks service");
if (history && bookmarks) {
// Update frecency *after* the visit info is in the db
nsresult rv = history->UpdateFrecency(
mData->placeId,
bookmarks->IsRealBookmark(mData->placeId)
);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Could not update frecency");
// Notify nsNavHistory observers of visit, but only for certain types of
// visits to maintain consistency with nsNavHistory::GetQueryResults.
if (!mData->hidden &&
mData->transitionType != nsINavHistoryService::TRANSITION_EMBED &&
mData->transitionType != nsINavHistoryService::TRANSITION_FRAMED_LINK) {
history->NotifyOnVisit(mData->uri, visitId, mData->dateTime,
mData->sessionId, mData->lastVisitId,
mData->transitionType);
}
}
nsCOMPtr<nsIObserverService> obsService =
mozilla::services::GetObserverService();
if (obsService) {
nsresult rv = obsService->NotifyObservers(mData->uri, URI_VISIT_SAVED, nsnull);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Could not notify observers");
}
History::GetService()->NotifyVisited(mData->uri);
return NS_OK;
}
protected:
nsAutoPtr<VisitURIData> mData;
};
NS_IMPL_ISUPPORTS1(
UpdateFrecencyAndNotifyStep
, mozIStorageStatementCallback
)
/**
* Step 5: Get newly created visit ID from moz_history_visits table.
*/
class GetVisitIDStep : public Step
{
public:
NS_DECL_ISUPPORTS
GetVisitIDStep(nsAutoPtr<VisitURIData> aData)
: mData(aData)
{
}
NS_IMETHOD Callback(mozIStorageResultSet* aResultSet)
{
// Find visit ID, needed for notifying observers in next step.
nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
nsCOMPtr<mozIStorageStatement> stmt =
history->GetStatementById(DB_RECENT_VISIT_OF_URL);
NS_ENSURE_STATE(stmt);
nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), mData->uri);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<Step> step = new UpdateFrecencyAndNotifyStep(mData);
rv = step->ExecuteAsync(stmt);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
protected:
nsAutoPtr<VisitURIData> mData;
};
NS_IMPL_ISUPPORTS1(
GetVisitIDStep
, mozIStorageStatementCallback
)
/**
* Step 4: Add visit to moz_history_visits table.
*/
class AddVisitStep : public Step
{
public:
NS_DECL_ISUPPORTS
AddVisitStep(nsAutoPtr<VisitURIData> aData)
: mData(aData)
{
}
NS_IMETHOD Callback(mozIStorageResultSet* aResultSet)
{
nsresult rv;
nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
// TODO need to figure out story for new session IDs that isn't synchronous
// (bug 561450)
if (aResultSet) {
// Result set contains last visit information for this session
nsCOMPtr<mozIStorageRow> row;
rv = aResultSet->GetNextRow(getter_AddRefs(row));
NS_ENSURE_SUCCESS(rv, rv);
PRInt64 possibleSessionId;
PRTime lastVisitOfSession;
rv = row->GetInt64(0, &mData->lastVisitId);
NS_ENSURE_SUCCESS(rv, rv);
rv = row->GetInt64(1, &possibleSessionId);
NS_ENSURE_SUCCESS(rv, rv);
rv = row->GetInt64(2, &lastVisitOfSession);
NS_ENSURE_SUCCESS(rv, rv);
if (mData->dateTime - lastVisitOfSession <= RECENT_EVENT_THRESHOLD) {
mData->sessionId = possibleSessionId;
}
else {
// Session is too old. Start a new one.
mData->sessionId = history->GetNewSessionID();
mData->lastVisitId = 0;
}
}
else {
// No previous saved visit entry could be found, so start a new session.
mData->sessionId = history->GetNewSessionID();
mData->lastVisitId = 0;
}
nsCOMPtr<mozIStorageStatement> stmt =
history->GetStatementById(DB_INSERT_VISIT);
NS_ENSURE_STATE(stmt);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("from_visit"),
mData->lastVisitId);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"),
mData->placeId);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("visit_date"),
mData->dateTime);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("visit_type"),
mData->transitionType);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("session"),
mData->sessionId);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<Step> step = new GetVisitIDStep(mData);
rv = step->ExecuteAsync(stmt);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
protected:
nsAutoPtr<VisitURIData> mData;
};
NS_IMPL_ISUPPORTS1(
AddVisitStep
, mozIStorageStatementCallback
)
/**
* Step 3: Callback for inserting or updating a moz_places entry.
* This step checks database for the last visit in session.
*/
class CheckLastVisitStep : public Step
{
public:
NS_DECL_ISUPPORTS
CheckLastVisitStep(nsAutoPtr<VisitURIData> aData)
: mData(aData)
{
}
NS_IMETHOD Callback(mozIStorageResultSet* aResultSet)
{
nsresult rv;
if (aResultSet) {
// Last step inserted a new URL. This query contains the id.
nsCOMPtr<mozIStorageRow> row;
rv = aResultSet->GetNextRow(getter_AddRefs(row));
NS_ENSURE_SUCCESS(rv, rv);
rv = row->GetInt64(0, &mData->placeId);
NS_ENSURE_SUCCESS(rv, rv);
}
if (!mData->lastSpec.IsEmpty()) {
// Find last visit ID and session ID using lastSpec so we can add them
// to a browsing session if the visit was recent.
nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
nsCOMPtr<mozIStorageStatement> stmt =
history->GetStatementById(DB_RECENT_VISIT_OF_URL);
NS_ENSURE_STATE(stmt);
rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), mData->lastSpec);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<Step> step = new AddVisitStep(mData);
rv = step->ExecuteAsync(stmt);
NS_ENSURE_SUCCESS(rv, rv);
}
else {
// Empty lastSpec.
// Not part of a session. Just run next step's callback with no results.
nsCOMPtr<Step> step = new AddVisitStep(mData);
rv = step->Callback(NULL);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
protected:
nsAutoPtr<VisitURIData> mData;
};
NS_IMPL_ISUPPORTS1(
CheckLastVisitStep
, mozIStorageStatementCallback
)
/**
* Step 2a: Called only when a new entry is put into moz_places.
* Finds the ID of a recently inserted place.
*/
class FindNewIdStep : public Step
{
public:
NS_DECL_ISUPPORTS
FindNewIdStep(nsAutoPtr<VisitURIData> aData)
: mData(aData)
{
}
NS_IMETHOD Callback(mozIStorageResultSet* aResultSet)
{
nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
nsCOMPtr<mozIStorageStatement> stmt =
history->GetStatementById(DB_GET_PAGE_VISIT_STATS);
NS_ENSURE_STATE(stmt);
nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), mData->uri);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<Step> step = new CheckLastVisitStep(mData);
rv = step->ExecuteAsync(stmt);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
protected:
nsAutoPtr<VisitURIData> mData;
};
NS_IMPL_ISUPPORTS1(
FindNewIdStep
, mozIStorageStatementCallback
)
/**
* Step 2: Callback for checking for an existing URI in moz_places.
* This step inserts or updates the URI accordingly.
*/
class CheckExistingStep : public Step
{
public:
NS_DECL_ISUPPORTS
CheckExistingStep(nsAutoPtr<VisitURIData> aData)
: mData(aData)
{
}
NS_IMETHOD Callback(mozIStorageResultSet* aResultSet)
{
nsresult rv;
nsCOMPtr<mozIStorageStatement> stmt;
nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
if (aResultSet) {
nsCOMPtr<mozIStorageRow> row;
rv = aResultSet->GetNextRow(getter_AddRefs(row));
NS_ENSURE_SUCCESS(rv, rv);
rv = row->GetInt64(0, &mData->placeId);
NS_ENSURE_SUCCESS(rv, rv);
if (!mData->typed) {
// If this transition wasn't typed, others might have been. If database
// has location as typed, reflect that in our data structure.
rv = row->GetInt32(2, &mData->typed);
NS_ENSURE_SUCCESS(rv, rv);
}
if (mData->hidden) {
// If this transition was hidden, it is possible that others were not.
// Any one visible transition makes this location visible. If database
// has location as visible, reflect that in our data structure.
rv = row->GetInt32(3, &mData->hidden);
NS_ENSURE_SUCCESS(rv, rv);
}
// Note: trigger will update visit_count.
stmt = history->GetStatementById(DB_UPDATE_PAGE_VISIT_STATS);
NS_ENSURE_STATE(stmt);
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("typed"), mData->typed);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("hidden"), mData->hidden);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt64ByName(NS_LITERAL_CSTRING("page_id"), mData->placeId);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<Step> step = new CheckLastVisitStep(mData);
rv = step->ExecuteAsync(stmt);
NS_ENSURE_SUCCESS(rv, rv);
}
else {
// No entry exists, so create one.
stmt = history->GetStatementById(DB_ADD_NEW_PAGE);
NS_ENSURE_STATE(stmt);
nsAutoString revHost;
rv = GetReversedHostname(mData->uri, revHost);
NS_ENSURE_SUCCESS(rv, rv);
rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), mData->uri);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindStringByName(NS_LITERAL_CSTRING("rev_host"), revHost);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("typed"), mData->typed);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("hidden"), mData->hidden);
NS_ENSURE_SUCCESS(rv, rv);
rv = stmt->BindInt32ByName(NS_LITERAL_CSTRING("frecency"), -1);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<Step> step = new FindNewIdStep(mData);
rv = step->ExecuteAsync(stmt);
NS_ENSURE_SUCCESS(rv, rv);
}
return NS_OK;
}
protected:
nsAutoPtr<VisitURIData> mData;
};
NS_IMPL_ISUPPORTS1(
CheckExistingStep
, mozIStorageStatementCallback
)
/**
* Step 1: See if there is an existing URI.
*/
class StartVisitURIStep : public Step
{
public:
NS_DECL_ISUPPORTS
StartVisitURIStep(nsAutoPtr<VisitURIData> aData)
: mData(aData)
{
}
NS_IMETHOD Callback(mozIStorageResultSet* aResultSet)
{
nsNavHistory* history = nsNavHistory::GetHistoryService();
// Find existing entry in moz_places table, if any.
nsCOMPtr<mozIStorageStatement> stmt =
history->GetStatementById(DB_GET_PAGE_VISIT_STATS);
NS_ENSURE_STATE(stmt);
nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), mData->uri);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<Step> step = new CheckExistingStep(mData);
rv = step->ExecuteAsync(stmt);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
protected:
nsAutoPtr<VisitURIData> mData;
};
NS_IMPL_ISUPPORTS1(
StartVisitURIStep
, Step
)
////////////////////////////////////////////////////////////////////////////////
//// Steps for SetURITitle
struct SetTitleData : public FailSafeFinishTask
{
nsCOMPtr<nsIURI> uri;
nsString title;
};
/**
* Step 3: Notify that title has been updated.
*/
class TitleNotifyStep: public Step
{
public:
NS_DECL_ISUPPORTS
TitleNotifyStep(nsAutoPtr<SetTitleData> aData)
: mData(aData)
{
}
NS_IMETHOD Callback(mozIStorageResultSet* aResultSet)
{
nsNavHistory* history = nsNavHistory::GetHistoryService();
history->NotifyTitleChange(mData->uri, mData->title);
return NS_OK;
}
protected:
nsAutoPtr<SetTitleData> mData;
};
NS_IMPL_ISUPPORTS1(
TitleNotifyStep
, mozIStorageStatementCallback
)
/**
* Step 2: Set title.
*/
class SetTitleStep : public Step
{
public:
NS_DECL_ISUPPORTS
SetTitleStep(nsAutoPtr<SetTitleData> aData)
: mData(aData)
{
}
NS_IMETHOD Callback(mozIStorageResultSet* aResultSet)
{
if (!aResultSet) {
// URI record was not found.
return NS_OK;
}
nsCOMPtr<mozIStorageRow> row;
nsresult rv = aResultSet->GetNextRow(getter_AddRefs(row));
NS_ENSURE_SUCCESS(rv, rv);
nsAutoString title;
rv = row->GetString(2, title);
NS_ENSURE_SUCCESS(rv, rv);
// It is actually common to set the title to be the same thing it used to
// be. For example, going to any web page will always cause a title to be set,
// even though it will often be unchanged since the last visit. In these
// cases, we can avoid DB writing and observer overhead.
if (mData->title.Equals(title) || (mData->title.IsVoid() && title.IsVoid()))
return NS_OK;
nsNavHistory* history = nsNavHistory::GetHistoryService();
nsCOMPtr<mozIStorageStatement> stmt =
history->GetStatementById(DB_SET_PLACE_TITLE);
NS_ENSURE_STATE(stmt);
if (mData->title.IsVoid()) {
rv = stmt->BindNullByName(NS_LITERAL_CSTRING("page_title"));
}
else {
rv = stmt->BindStringByName(
NS_LITERAL_CSTRING("page_title"),
StringHead(mData->title, TITLE_LENGTH_MAX)
);
}
NS_ENSURE_SUCCESS(rv, rv);
rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), mData->uri);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<Step> step = new TitleNotifyStep(mData);
rv = step->ExecuteAsync(stmt);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
protected:
nsAutoPtr<SetTitleData> mData;
};
NS_IMPL_ISUPPORTS1(
SetTitleStep
, mozIStorageStatementCallback
)
/**
* Step 1: See if there is an existing URI.
*/
class StartSetURITitleStep : public Step
{
public:
NS_DECL_ISUPPORTS
StartSetURITitleStep(nsAutoPtr<SetTitleData> aData)
: mData(aData)
{
}
NS_IMETHOD Callback(mozIStorageResultSet* aResultSet)
{
nsNavHistory* history = nsNavHistory::GetHistoryService();
// Find existing entry in moz_places table, if any.
nsCOMPtr<mozIStorageStatement> stmt =
history->GetStatementById(DB_GET_URL_PAGE_INFO);
NS_ENSURE_STATE(stmt);
nsresult rv = URIBinder::Bind(stmt, NS_LITERAL_CSTRING("page_url"), mData->uri);
NS_ENSURE_SUCCESS(rv, rv);
nsCOMPtr<Step> step = new SetTitleStep(mData);
rv = step->ExecuteAsync(stmt);
NS_ENSURE_SUCCESS(rv, rv);
return NS_OK;
}
protected:
nsAutoPtr<SetTitleData> mData;
};
NS_IMPL_ISUPPORTS1(
StartSetURITitleStep
, Step
)
} // anonymous namespace
////////////////////////////////////////////////////////////////////////////////
@ -862,43 +160,12 @@ History::History()
History::~History()
{
gService = NULL;
#ifdef DEBUG
if (mObservers.IsInitialized()) {
NS_ASSERTION(mObservers.Count() == 0,
"Not all Links were removed before we disappear!");
}
#endif
NS_WARN_IF_FALSE(!mPendingVisits.PeekFront(), "Tasks were not completed :(");
// History is going away, so abandon tasks.
while (mPendingVisits.PeekFront()) {
nsCOMPtr<Step> deadTaskWalking =
dont_AddRef(static_cast<Step*>(mPendingVisits.PopFront()));
}
}
void
History::AppendTask(Step* aTask)
{
NS_PRECONDITION(aTask, "Got NULL task.");
NS_ADDREF(aTask);
mPendingVisits.Push(aTask);
if (mPendingVisits.GetSize() == 1) {
// There are no other pending tasks.
StartNextTask();
}
}
void
History::CurrentTaskFinished()
{
nsCOMPtr<Step> deadTaskWalking =
dont_AddRef(static_cast<Step*>(mPendingVisits.PopFront()));
StartNextTask();
}
void
@ -961,107 +228,9 @@ History::GetSingleton()
return gService;
}
void
History::StartNextTask()
{
nsCOMPtr<Step> nextTask =
static_cast<Step*>(mPendingVisits.PeekFront());
if (!nextTask) {
// No more pending visits left to process.
return;
}
nsresult rv = nextTask->Callback(NULL);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Beginning a task failed.");
}
////////////////////////////////////////////////////////////////////////////////
//// IHistory
NS_IMETHODIMP
History::VisitURI(nsIURI* aURI,
nsIURI* aLastVisitedURI,
PRUint32 aFlags)
{
NS_PRECONDITION(aURI, "URI should not be NULL.");
nsNavHistory* history = nsNavHistory::GetHistoryService();
NS_ENSURE_TRUE(history, NS_ERROR_OUT_OF_MEMORY);
// Silently return if URI is something we shouldn't add to DB.
PRBool canAdd;
nsresult rv = history->CanAddURI(aURI, &canAdd);
NS_ENSURE_SUCCESS(rv, rv);
if (!canAdd) {
return NS_OK;
}
// Populate data structure that will be used in our async SQL steps.
nsAutoPtr<VisitURIData> data(new VisitURIData());
nsCAutoString spec;
rv = aURI->GetSpec(spec);
NS_ENSURE_SUCCESS(rv, rv);
if (aLastVisitedURI) {
rv = aLastVisitedURI->GetSpec(data->lastSpec);
NS_ENSURE_SUCCESS(rv, rv);
}
if (spec.Equals(data->lastSpec)) {
// Do not save refresh-page visits.
return NS_OK;
}
// Assigns a type to the edge in the visit linked list. Each type will be
// considered differently when weighting the frecency of a location.
PRUint32 recentFlags = history->GetRecentFlags(aURI);
bool redirected = false;
if (aFlags & IHistory::REDIRECT_TEMPORARY) {
data->transitionType = nsINavHistoryService::TRANSITION_REDIRECT_TEMPORARY;
redirected = true;
}
else if (aFlags & IHistory::REDIRECT_PERMANENT) {
data->transitionType = nsINavHistoryService::TRANSITION_REDIRECT_PERMANENT;
redirected = true;
}
else if (recentFlags & nsNavHistory::RECENT_TYPED) {
data->transitionType = nsINavHistoryService::TRANSITION_TYPED;
}
else if (recentFlags & nsNavHistory::RECENT_BOOKMARKED) {
data->transitionType = nsINavHistoryService::TRANSITION_BOOKMARK;
}
else if (aFlags & IHistory::TOP_LEVEL) {
// User was redirected or link was clicked in the main window.
data->transitionType = nsINavHistoryService::TRANSITION_LINK;
}
else if (recentFlags & nsNavHistory::RECENT_ACTIVATED) {
// User activated a link in a frame.
data->transitionType = nsINavHistoryService::TRANSITION_FRAMED_LINK;
}
else {
// A frame redirected to a new site without user interaction.
data->transitionType = nsINavHistoryService::TRANSITION_EMBED;
}
data->typed = (data->transitionType == nsINavHistoryService::TRANSITION_TYPED) ? 1 : 0;
data->hidden =
(data->transitionType == nsINavHistoryService::TRANSITION_FRAMED_LINK ||
data->transitionType == nsINavHistoryService::TRANSITION_EMBED ||
redirected) ? 1 : 0;
data->dateTime = PR_Now();
data->uri = aURI;
nsCOMPtr<Step> task(new StartVisitURIStep(data));
AppendTask(task);
nsCOMPtr<nsIObserverService> obsService =
mozilla::services::GetObserverService();
if (obsService) {
obsService->NotifyObservers(aURI, NS_LINK_VISITED_EVENT_TOPIC, nsnull);
}
return NS_OK;
}
NS_IMETHODIMP
History::RegisterVisitedCallback(nsIURI* aURI,
Link* aLink)
@ -1139,42 +308,12 @@ History::UnregisterVisitedCallback(nsIURI* aURI,
return NS_OK;
}
NS_IMETHODIMP
History::SetURITitle(nsIURI* aURI, const nsAString& aTitle)
{
NS_PRECONDITION(aURI, "Must pass a non-null URI!");
nsNavHistory* history = nsNavHistory::GetHistoryService();
PRBool canAdd;
nsresult rv = history->CanAddURI(aURI, &canAdd);
NS_ENSURE_SUCCESS(rv, rv);
if (!canAdd) {
return NS_OK;
}
nsAutoPtr<SetTitleData> data(new SetTitleData());
data->uri = aURI;
if (aTitle.IsEmpty()) {
data->title.SetIsVoid(PR_TRUE);
}
else {
data->title.Assign(aTitle);
}
nsCOMPtr<Step> task(new StartSetURITitleStep(data));
AppendTask(task);
return NS_OK;
}
////////////////////////////////////////////////////////////////////////////////
//// nsISupports
NS_IMPL_ISUPPORTS1(
History
, IHistory
History,
IHistory
)
} // namespace places

View File

@ -46,13 +46,12 @@
#include "nsString.h"
#include "nsURIHashKey.h"
#include "nsTArray.h"
#include "nsDeque.h"
namespace mozilla {
namespace places {
#define NS_HISTORYSERVICE_CID \
{0x0937a705, 0x91a6, 0x417a, {0x82, 0x92, 0xb2, 0x2e, 0xb1, 0x0d, 0xa8, 0x6c}}
{0x9fc91e65, 0x1475, 0x4353, {0x9b, 0x9a, 0x93, 0xd7, 0x6f, 0x5b, 0xd9, 0xb7}}
class History : public IHistory
{
@ -70,26 +69,6 @@ public:
*/
void NotifyVisited(nsIURI *aURI);
/**
* Append a task to the queue for SQL queries that need to happen
* atomically.
*
* @pre aTask is not null
*
* @param aTask
* Task that needs to be completed atomically
*/
void AppendTask(class Step* aTask);
/**
* Call when all steps of the current running task are finished. Each task
* should be responsible for calling this when it is finished (even if there
* are errors).
*
* Do not call this twice for the same visit.
*/
void CurrentTaskFinished();
/**
* Obtains a pointer to this service.
*/
@ -104,26 +83,6 @@ public:
private:
~History();
/**
* Since visits rapidly fire at once, it's very likely to have race
* conditions for SQL queries. We often need to see if a row exists
* or peek at values, and by the time we have retrieved them they could
* be different.
*
* We guarantee an ordering of our SQL statements so that a set of
* callbacks for one visit are guaranteed to be atomic. Each visit consists
* of a data structure that sits in this queue.
*
* The front of the queue always has the current visit we are processing.
*/
nsDeque mPendingVisits;
/**
* Begins next task at the front of the queue. The task remains in the queue
* until it is done and calls CurrentTaskFinished.
*/
void StartNextTask();
static History *gService;
typedef nsTArray<mozilla::dom::Link *> ObserverArray;

View File

@ -88,6 +88,11 @@
using namespace mozilla::places;
// Microsecond timeout for "recent" events such as typed and bookmark following.
// If you typed it more than this time ago, it's not recent.
// This is 15 minutes m s/m us/s
#define RECENT_EVENT_THRESHOLD PRTime((PRInt64)15 * 60 * PR_USEC_PER_SEC)
// The maximum number of things that we will store in the recent events list
// before calling ExpireNonrecentEvents. This number should be big enough so it
// is very difficult to get that many unconsumed events (for example, typed but
@ -232,12 +237,21 @@ NS_IMPL_CI_INTERFACE_GETTER5(
namespace {
static nsresult GetReversedHostname(nsIURI* aURI, nsAString& host);
static void GetReversedHostname(const nsString& aForward, nsAString& aReversed);
static PRInt64 GetSimpleBookmarksQueryFolder(
const nsCOMArray<nsNavHistoryQuery>& aQueries,
nsNavHistoryQueryOptions* aOptions);
static void ParseSearchTermsFromQueries(const nsCOMArray<nsNavHistoryQuery>& aQueries,
nsTArray<nsTArray<nsString>*>* aTerms);
inline void ReverseString(const nsString& aInput, nsAString& aReversed)
{
aReversed.Truncate(0);
for (PRInt32 i = aInput.Length() - 1; i >= 0; i --)
aReversed.Append(aInput[i]);
}
} // anonymous namespace
namespace mozilla {
@ -895,27 +909,6 @@ nsNavHistory::UpdateSchemaVersion()
}
PRUint32
nsNavHistory::GetRecentFlags(nsIURI *aURI)
{
PRUint32 result = 0;
nsCAutoString spec;
nsresult rv = aURI->GetSpec(spec);
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Unable to get aURI's spec");
if (NS_SUCCEEDED(rv)) {
if (CheckIsRecentEvent(&mRecentTyped, spec))
result |= RECENT_TYPED;
if (CheckIsRecentEvent(&mRecentLink, spec))
result |= RECENT_ACTIVATED;
if (CheckIsRecentEvent(&mRecentBookmark, spec))
result |= RECENT_BOOKMARKED;
}
return result;
}
/**
* Called after InitDB, this creates our own functions
*/
@ -1872,9 +1865,6 @@ nsNavHistory::GetUrlIdFor(nsIURI* aURI, PRInt64* aEntryID,
// THIS SHOULD BE THE ONLY PLACE NEW moz_places ROWS ARE
// CREATED. This allows us to maintain better consistency.
//
// XXX this functionality is being moved to History.cpp, so
// in fact there *are* two places where new pages are added.
//
// If non-null, the new page ID will be placed into aPageID.
nsresult
@ -2172,29 +2162,6 @@ nsNavHistory::GetNewSessionID()
}
void
nsNavHistory::NotifyOnVisit(nsIURI* aURI,
PRInt64 aVisitID,
PRTime aTime,
PRInt64 aSessionID,
PRInt64 referringVisitID,
PRInt32 aTransitionType)
{
PRUint32 added = 0;
NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
nsINavHistoryObserver,
OnVisit(aURI, aVisitID, aTime, aSessionID,
referringVisitID, aTransitionType, &added));
}
void
nsNavHistory::NotifyTitleChange(nsIURI* aURI, const nsString& aTitle)
{
NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
nsINavHistoryObserver, OnTitleChanged(aURI, aTitle));
}
PRInt32
nsNavHistory::GetDaysOfHistory() {
PRInt32 daysOfHistory = 0;
@ -2899,9 +2866,12 @@ nsNavHistory::AddVisit(nsIURI* aURI, PRTime aTime, nsIURI* aReferringURI,
// Notify observers: The hidden detection code must match that in
// GetQueryResults to maintain consistency.
// FIXME bug 325241: make a way to observe hidden URLs
PRUint32 added = 0;
if (!hidden) {
NotifyOnVisit(aURI, *aVisitID, aTime, aSessionID, referringVisitID,
aTransitionType);
NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
nsINavHistoryObserver,
OnVisit(aURI, *aVisitID, aTime, aSessionID,
referringVisitID, aTransitionType, &added));
}
// Normally docshell sends the link visited observer notification for us (this
@ -7365,6 +7335,7 @@ nsNavHistory::SetPageTitleInternal(nsIURI* aURI, const nsAString& aTitle)
rv = mDBSetPlaceTitle->Execute();
NS_ENSURE_SUCCESS(rv, rv);
// observers (have to check first if it's bookmarked)
NOTIFY_OBSERVERS(mCanNotify, mCacheObservers, mObservers,
nsINavHistoryObserver, OnTitleChanged(aURI, aTitle));
@ -7576,6 +7547,52 @@ nsNavHistory::RemoveDuplicateURIs()
namespace {
// GetReversedHostname
//
// This extracts the hostname from the URI and reverses it in the
// form that we use (always ending with a "."). So
// "http://microsoft.com/" becomes "moc.tfosorcim."
//
// The idea behind this is that we can create an index over the items in
// the reversed host name column, and then query for as much or as little
// of the host name as we feel like.
//
// For example, the query "host >= 'gro.allizom.' AND host < 'gro.allizom/'
// Matches all host names ending in '.mozilla.org', including
// 'developer.mozilla.org' and just 'mozilla.org' (since we define all
// reversed host names to end in a period, even 'mozilla.org' matches).
// The important thing is that this operation uses the index. Any substring
// calls in a select statement (even if it's for the beginning of a string)
// will bypass any indices and will be slow).
nsresult
GetReversedHostname(nsIURI* aURI, nsAString& aRevHost)
{
nsCString forward8;
nsresult rv = aURI->GetHost(forward8);
if (NS_FAILED(rv)) {
return rv;
}
// can't do reversing in UTF8, better use 16-bit chars
NS_ConvertUTF8toUTF16 forward(forward8);
GetReversedHostname(forward, aRevHost);
return NS_OK;
}
// GetReversedHostname
//
// Same as previous but for strings
void
GetReversedHostname(const nsString& aForward, nsAString& aRevHost)
{
ReverseString(aForward, aRevHost);
aRevHost.Append(PRUnichar('.'));
}
// GetSimpleBookmarksQueryFolder
//
// Determines if this set of queries is a simple bookmarks query for a

View File

@ -88,10 +88,6 @@
#define URI_LENGTH_MAX 65536
#define TITLE_LENGTH_MAX 4096
// Microsecond timeout for "recent" events such as typed and bookmark following.
// If you typed it more than this time ago, it's not recent.
#define RECENT_EVENT_THRESHOLD PRTime((PRInt64)15 * 60 * PR_USEC_PER_SEC)
#ifdef MOZ_XUL
// Fired after autocomplete feedback has been updated.
#define TOPIC_AUTOCOMPLETE_FEEDBACK_UPDATED "places-autocomplete-feedback-updated"
@ -116,13 +112,6 @@ namespace places {
DB_GET_PAGE_INFO_BY_URL = 0
, DB_GET_TAGS = 1
, DB_IS_PAGE_VISITED = 2
, DB_INSERT_VISIT = 3
, DB_RECENT_VISIT_OF_URL = 4
, DB_GET_PAGE_VISIT_STATS = 5
, DB_UPDATE_PAGE_VISIT_STATS = 6
, DB_ADD_NEW_PAGE = 7
, DB_GET_URL_PAGE_INFO = 8
, DB_SET_PLACE_TITLE = 9
};
} // namespace places
@ -405,19 +394,6 @@ public:
*/
bool canNotify() { return mCanNotify; }
enum RecentEventFlags {
RECENT_TYPED = 1 << 0, // User typed in URL recently
RECENT_ACTIVATED = 1 << 1, // User tapped URL link recently
RECENT_BOOKMARKED = 1 << 2 // User bookmarked URL recently
};
/**
* Returns any recent activity done with a URL.
* @return Any recent events associated with this URI. Each bit is set
* according to RecentEventFlags enum values.
*/
PRUint32 GetRecentFlags(nsIURI *aURI);
mozIStorageStatement* GetStatementById(
enum mozilla::places::HistoryStatementId aStatementId
)
@ -430,41 +406,10 @@ public:
return mDBGetTags;
case DB_IS_PAGE_VISITED:
return mDBIsPageVisited;
case DB_INSERT_VISIT:
return mDBInsertVisit;
case DB_RECENT_VISIT_OF_URL:
return mDBRecentVisitOfURL;
case DB_GET_PAGE_VISIT_STATS:
return mDBGetPageVisitStats;
case DB_UPDATE_PAGE_VISIT_STATS:
return mDBUpdatePageVisitStats;
case DB_ADD_NEW_PAGE:
return mDBAddNewPage;
case DB_GET_URL_PAGE_INFO:
return mDBGetURLPageInfo;
case DB_SET_PLACE_TITLE:
return mDBSetPlaceTitle;
}
return nsnull;
}
PRInt64 GetNewSessionID();
/**
* Fires onVisit event to nsINavHistoryService observers
*/
void NotifyOnVisit(nsIURI* aURI,
PRInt64 aVisitID,
PRTime aTime,
PRInt64 aSessionID,
PRInt64 referringVisitID,
PRInt32 aTransitionType);
/**
* Fires onTitleChanged event to nsINavHistoryService observers
*/
void NotifyTitleChange(nsIURI* aURI, const nsString& title);
private:
~nsNavHistory();
@ -742,6 +687,7 @@ protected:
// Sessions tracking.
PRInt64 mLastSessionID;
PRInt64 GetNewSessionID();
#ifdef MOZ_XUL
// AutoComplete stuff

View File

@ -47,8 +47,6 @@ include $(topsrcdir)/config/rules.mk
_BROWSER_FILES = \
browser_bug399606.js \
browser_visituri.js \
browser_settitle.js \
$(NULL)
# These are files that need to be loaded via the HTTP proxy server
@ -60,12 +58,6 @@ _HTTP_FILES = \
bug_399606/399606-window.location.href.html \
bug_399606/399606-window.location.html \
bug_399606/399606-history.go-0.html \
visituri/begin.html \
visituri/redirect_twice.sjs \
visituri/redirect_once.sjs \
visituri/final.html \
settitle/title1.html \
settitle/title2.html \
$(NULL)
libs:: $(_BROWSER_FILES)

View File

@ -47,9 +47,6 @@
#include "nsINavHistoryService.h"
#include "nsIObserverService.h"
#include "mozilla/IHistory.h"
#include "mozIStorageConnection.h"
#include "mozIStorageStatement.h"
#include "nsPIPlacesDatabase.h"
using namespace mozilla;
@ -120,21 +117,6 @@ addURI(nsIURI* aURI)
do_check_success(rv);
}
struct PlaceRecord
{
PRInt64 id;
PRInt32 hidden;
PRInt32 typed;
PRInt32 visitCount;
};
struct VisitRecord
{
PRInt64 id;
PRInt64 lastVisitId;
PRInt32 transitionType;
};
already_AddRefed<IHistory>
do_get_IHistory()
{
@ -142,107 +124,3 @@ do_get_IHistory()
do_check_true(history);
return history.forget();
}
already_AddRefed<nsINavHistoryService>
do_get_NavHistory()
{
nsCOMPtr<nsINavHistoryService> serv =
do_GetService(NS_NAVHISTORYSERVICE_CONTRACTID);
do_check_true(serv);
return serv.forget();
}
already_AddRefed<mozIStorageConnection>
do_get_db()
{
nsCOMPtr<nsINavHistoryService> history = do_get_NavHistory();
nsCOMPtr<nsPIPlacesDatabase> database = do_QueryInterface(history);
do_check_true(database);
mozIStorageConnection* dbConn;
nsresult rv = database->GetDBConnection(&dbConn);
do_check_success(rv);
return dbConn;
}
/**
* Get the place record from the database.
*
* @param aURI The unique URI of the place we are looking up
* @param result Out parameter where the result is stored
*/
void
do_get_place(nsIURI* aURI, PlaceRecord& result)
{
nsCOMPtr<mozIStorageConnection> dbConn = do_get_db();
nsCOMPtr<mozIStorageStatement> stmt;
nsCString spec;
nsresult rv = aURI->GetSpec(spec);
do_check_success(rv);
rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT id, hidden, typed, visit_count FROM moz_places_temp "
"WHERE url=?1 "
"UNION ALL "
"SELECT id, hidden, typed, visit_count FROM moz_places "
"WHERE url=?1 "
"LIMIT 1"
), getter_AddRefs(stmt));
do_check_success(rv);
rv = stmt->BindUTF8StringParameter(0, spec);
do_check_success(rv);
PRBool hasResults;
rv = stmt->ExecuteStep(&hasResults);
do_check_true(hasResults);
do_check_success(rv);
rv = stmt->GetInt64(0, &result.id);
do_check_success(rv);
rv = stmt->GetInt32(1, &result.hidden);
do_check_success(rv);
rv = stmt->GetInt32(2, &result.typed);
do_check_success(rv);
rv = stmt->GetInt32(3, &result.visitCount);
do_check_success(rv);
}
/**
* Gets the most recent visit to a place.
*
* @param placeID ID from the moz_places table
* @param result Out parameter where visit is stored
*/
void
do_get_lastVisit(PRInt64 placeId, VisitRecord& result)
{
nsCOMPtr<mozIStorageConnection> dbConn = do_get_db();
nsCOMPtr<mozIStorageStatement> stmt;
nsresult rv = dbConn->CreateStatement(NS_LITERAL_CSTRING(
"SELECT id, from_visit, visit_type FROM moz_historyvisits_temp "
"WHERE place_id=?1 "
"UNION ALL "
"SELECT id, from_visit, visit_type FROM moz_historyvisits "
"WHERE place_id=?1 "
"LIMIT 1"
), getter_AddRefs(stmt));
do_check_success(rv);
rv = stmt->BindInt64Parameter(0, placeId);
do_check_success(rv);
PRBool hasResults;
rv = stmt->ExecuteStep(&hasResults);
do_check_true(hasResults);
do_check_success(rv);
rv = stmt->GetInt64(0, &result.id);
do_check_success(rv);
rv = stmt->GetInt64(1, &result.lastVisitId);
do_check_success(rv);
rv = stmt->GetInt32(2, &result.transitionType);
do_check_success(rv);
}

View File

@ -38,7 +38,6 @@
* ***** END LICENSE BLOCK ***** */
#include "places_test_harness.h"
#include "nsIBrowserHistory.h"
#include "mock_Link.h"
using namespace mozilla::dom;
@ -77,53 +76,6 @@ new_test_uri()
return testURI.forget();
}
class VisitURIObserver : public nsIObserver
{
public:
NS_DECL_ISUPPORTS
VisitURIObserver(int aExpectedVisits = 1) :
mVisits(0),
mExpectedVisits(aExpectedVisits)
{
nsCOMPtr<nsIObserverService> observerService =
do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
do_check_true(observerService);
(void)observerService->AddObserver(this,
"uri-visit-saved",
PR_FALSE);
}
void WaitForNotification()
{
while (mVisits < mExpectedVisits) {
(void)NS_ProcessNextEvent();
}
}
NS_IMETHOD Observe(nsISupports* aSubject,
const char* aTopic,
const PRUnichar* aData)
{
mVisits++;
if (mVisits == mExpectedVisits) {
nsCOMPtr<nsIObserverService> observerService =
do_GetService(NS_OBSERVERSERVICE_CONTRACTID);
(void)observerService->RemoveObserver(this, "uri-visit-saved");
}
return NS_OK;
}
private:
int mVisits;
int mExpectedVisits;
};
NS_IMPL_ISUPPORTS1(
VisitURIObserver,
nsIObserver
)
////////////////////////////////////////////////////////////////////////////////
//// Test Functions
@ -411,145 +363,6 @@ test_observer_topic_dispatched()
run_next_test();
}
void
test_visituri_inserts()
{
nsCOMPtr<IHistory> history(do_get_IHistory());
nsCOMPtr<nsIURI> lastURI(new_test_uri());
nsCOMPtr<nsIURI> visitedURI(new_test_uri());
history->VisitURI(visitedURI, lastURI, mozilla::IHistory::TOP_LEVEL);
nsCOMPtr<VisitURIObserver> finisher = new VisitURIObserver();
finisher->WaitForNotification();
PlaceRecord place;
do_get_place(visitedURI, place);
do_check_true(place.id > 0);
do_check_false(place.hidden);
do_check_false(place.typed);
do_check_true(place.visitCount == 1);
run_next_test();
}
void
test_visituri_updates()
{
nsCOMPtr<IHistory> history(do_get_IHistory());
nsCOMPtr<nsIURI> lastURI(new_test_uri());
nsCOMPtr<nsIURI> visitedURI(new_test_uri());
nsCOMPtr<VisitURIObserver> finisher;
history->VisitURI(visitedURI, lastURI, mozilla::IHistory::TOP_LEVEL);
finisher = new VisitURIObserver();
finisher->WaitForNotification();
history->VisitURI(visitedURI, lastURI, mozilla::IHistory::TOP_LEVEL);
finisher = new VisitURIObserver();
finisher->WaitForNotification();
PlaceRecord place;
do_get_place(visitedURI, place);
do_check_true(place.visitCount == 2);
run_next_test();
}
void
test_visituri_preserves_shown_and_typed()
{
nsCOMPtr<IHistory> history(do_get_IHistory());
nsCOMPtr<nsIURI> lastURI(new_test_uri());
nsCOMPtr<nsIURI> visitedURI(new_test_uri());
history->VisitURI(visitedURI, lastURI, mozilla::IHistory::TOP_LEVEL);
// this simulates the uri visit happening in a frame. Normally frame
// transitions would be hidden unless it was previously loaded top-level
history->VisitURI(visitedURI, lastURI, 0);
nsCOMPtr<VisitURIObserver> finisher = new VisitURIObserver(2);
finisher->WaitForNotification();
PlaceRecord place;
do_get_place(visitedURI, place);
do_check_false(place.hidden);
run_next_test();
}
void
test_visituri_creates_visit()
{
nsCOMPtr<IHistory> history(do_get_IHistory());
nsCOMPtr<nsIURI> lastURI(new_test_uri());
nsCOMPtr<nsIURI> visitedURI(new_test_uri());
history->VisitURI(visitedURI, lastURI, mozilla::IHistory::TOP_LEVEL);
nsCOMPtr<VisitURIObserver> finisher = new VisitURIObserver();
finisher->WaitForNotification();
PlaceRecord place;
VisitRecord visit;
do_get_place(visitedURI, place);
do_get_lastVisit(place.id, visit);
do_check_true(visit.id > 0);
do_check_true(visit.lastVisitId == 0);
do_check_true(visit.transitionType == nsINavHistoryService::TRANSITION_LINK);
run_next_test();
}
void
test_visituri_transition_typed()
{
nsCOMPtr<nsINavHistoryService> navHistory = do_get_NavHistory();
nsCOMPtr<nsIBrowserHistory> browserHistory = do_QueryInterface(navHistory);
nsCOMPtr<IHistory> history(do_get_IHistory());
nsCOMPtr<nsIURI> lastURI(new_test_uri());
nsCOMPtr<nsIURI> visitedURI(new_test_uri());
browserHistory->MarkPageAsTyped(visitedURI);
history->VisitURI(visitedURI, lastURI, mozilla::IHistory::TOP_LEVEL);
nsCOMPtr<VisitURIObserver> finisher = new VisitURIObserver();
finisher->WaitForNotification();
PlaceRecord place;
VisitRecord visit;
do_get_place(visitedURI, place);
do_get_lastVisit(place.id, visit);
do_check_true(visit.transitionType == nsINavHistoryService::TRANSITION_TYPED);
run_next_test();
}
void
test_visituri_transition_embed()
{
nsCOMPtr<nsINavHistoryService> navHistory = do_get_NavHistory();
nsCOMPtr<nsIBrowserHistory> browserHistory = do_QueryInterface(navHistory);
nsCOMPtr<IHistory> history(do_get_IHistory());
nsCOMPtr<nsIURI> lastURI(new_test_uri());
nsCOMPtr<nsIURI> visitedURI(new_test_uri());
history->VisitURI(visitedURI, lastURI, 0);
nsCOMPtr<VisitURIObserver> finisher = new VisitURIObserver();
finisher->WaitForNotification();
PlaceRecord place;
VisitRecord visit;
do_get_place(visitedURI, place);
do_get_lastVisit(place.id, visit);
do_check_true(visit.transitionType == nsINavHistoryService::TRANSITION_EMBED);
run_next_test();
}
////////////////////////////////////////////////////////////////////////////////
//// Test Harness
@ -565,12 +378,6 @@ Test gTests[] = {
TEST(test_new_visit_notifies_waiting_Link),
TEST(test_RegisterVisitedCallback_returns_before_notifying),
TEST(test_observer_topic_dispatched),
TEST(test_visituri_inserts),
TEST(test_visituri_updates),
TEST(test_visituri_preserves_shown_and_typed),
TEST(test_visituri_creates_visit),
TEST(test_visituri_transition_typed),
TEST(test_visituri_transition_embed),
};
const char* file = __FILE__;

View File

@ -113,7 +113,6 @@ LOCAL_INCLUDES = \
-I$(srcdir)/../threads/_xpidlgen \
-I$(srcdir)/../proxy/src \
-I$(srcdir)/../reflect/xptinfo/src \
-I$(srcdir)/../../docshell/base \
$(NULL)
EXPORTS_NAMESPACES = mozilla

View File

@ -5,14 +5,3 @@ MOZ_SERVICE(XULOverlayProviderService, nsIXULOverlayProvider, "@mozilla.org/chro
MOZ_SERVICE(IOService, nsIIOService, "@mozilla.org/network/io-service;1")
MOZ_SERVICE(ObserverService, nsIObserverService, "@mozilla.org/observer-service;1")
MOZ_SERVICE(StringBundleService, nsIStringBundleService, "@mozilla.org/intl/stringbundle;1")
#ifdef MOZ_USE_NAMESPACE
namespace mozilla
{
#endif
MOZ_SERVICE(HistoryService, IHistory, "@mozilla.org/browser/history;1")
#ifdef MOZ_USE_NAMESPACE
}
#endif

View File

@ -48,9 +48,7 @@
#include "nsIStringBundle.h"
#include "nsIToolkitChromeRegistry.h"
#include "nsIXULOverlayProvider.h"
#include "IHistory.h"
using namespace mozilla;
using namespace mozilla::services;
/*

View File

@ -42,12 +42,9 @@
#include "nscore.h"
#include "nsCOMPtr.h"
#define MOZ_USE_NAMESPACE
#define MOZ_SERVICE(NAME, TYPE, SERVICE_CID) class TYPE;
#include "ServiceList.h"
#undef MOZ_SERVICE
#undef MOZ_USE_NAMESPACE
namespace mozilla {
namespace services {