Bug 500328 - Implement History.pushState(), History.replaceState() methods. r=smaug, r=zpao, sr=sicking

This commit is contained in:
Justin Lebar
2009-09-01 09:45:05 -07:00
parent e891b712e7
commit 3bf83e55ef
54 changed files with 2155 additions and 130 deletions

View File

@@ -109,6 +109,7 @@
#include "nsIURIClassifier.h"
#include "nsIOfflineCacheUpdate.h"
#include "nsCPrefetchService.h"
#include "nsJSON.h"
// we want to explore making the document own the load group
// so we can associate the document URI with the load group.
@@ -655,6 +656,8 @@ DispatchPings(nsIContent *content, nsIURI *referrer)
ForEachPing(content, SendPing, &info);
}
static nsISHEntry* GetRootSHEntry(nsISHEntry *entry);
//*****************************************************************************
//*** nsDocShell: Object Management
//*****************************************************************************
@@ -863,6 +866,14 @@ NS_IMETHODIMP nsDocShell::GetInterface(const nsIID & aIID, void **aSink)
mContentViewer->GetDOMDocument((nsIDOMDocument **) aSink);
return *aSink ? NS_OK : NS_NOINTERFACE;
}
else if (aIID.Equals(NS_GET_IID(nsIDocument)) &&
NS_SUCCEEDED(EnsureContentViewer())) {
nsCOMPtr<nsIDOMDocument> domDoc;
mContentViewer->GetDOMDocument(getter_AddRefs(domDoc));
if (!domDoc)
return NS_NOINTERFACE;
return domDoc->QueryInterface(aIID, aSink);
}
else if (aIID.Equals(NS_GET_IID(nsIApplicationCacheContainer))) {
*aSink = nsnull;
@@ -1196,7 +1207,7 @@ nsDocShell::LoadURI(nsIURI * aURI,
// The parent was loaded normally. In this case, this *brand new* child really shouldn't
// have a SHEntry. If it does, it could be because the parent is replacing an
// existing frame with a new frame, in the onLoadHandler. We don't want this
// url to get into session history. Clear off shEntry, and set laod type to
// url to get into session history. Clear off shEntry, and set load type to
// LOAD_BYPASS_HISTORY.
PRBool inOnLoadHandler=PR_FALSE;
parentDS->GetIsExecutingOnLoadHandler(&inOnLoadHandler);
@@ -3226,11 +3237,11 @@ nsDocShell::GetChildSHEntry(PRInt32 aChildOffset, nsISHEntry ** aResult)
NS_IMETHODIMP
nsDocShell::AddChildSHEntry(nsISHEntry * aCloneRef, nsISHEntry * aNewEntry,
PRInt32 aChildOffset)
PRInt32 aChildOffset, PRUint32 loadType)
{
nsresult rv;
if (mLSHE) {
if (mLSHE && loadType != LOAD_PUSHSTATE) {
/* You get here if you are currently building a
* hierarchy ie.,you just visited a frameset page
*/
@@ -3285,7 +3296,8 @@ nsDocShell::AddChildSHEntry(nsISHEntry * aCloneRef, nsISHEntry * aNewEntry,
nsCOMPtr<nsIDocShellHistory> parent =
do_QueryInterface(GetAsSupports(mParent), &rv);
if (parent) {
rv = parent->AddChildSHEntry(aCloneRef, aNewEntry, aChildOffset);
rv = parent->AddChildSHEntry(aCloneRef, aNewEntry, aChildOffset,
loadType);
}
}
return rv;
@@ -3313,7 +3325,7 @@ nsDocShell::DoAddChildSHEntry(nsISHEntry* aNewEntry, PRInt32 aChildOffset)
nsCOMPtr<nsIDocShellHistory> parent =
do_QueryInterface(GetAsSupports(mParent), &rv);
if (parent) {
rv = parent->AddChildSHEntry(mOSHE, aNewEntry, aChildOffset);
rv = parent->AddChildSHEntry(mOSHE, aNewEntry, aChildOffset, mLoadType);
}
@@ -3457,7 +3469,6 @@ NS_IMETHODIMP nsDocShell::GotoIndex(PRInt32 aIndex)
}
NS_IMETHODIMP
nsDocShell::LoadURI(const PRUnichar * aURI,
PRUint32 aLoadFlags,
@@ -3846,6 +3857,13 @@ nsDocShell::LoadErrorPage(nsIURI *aURI, const PRUnichar *aURL,
mFailedURI = aURI;
mFailedLoadType = mLoadType;
if (mLSHE) {
// If we don't give mLSHE a new doc identifier here, when we go back or
// forward to another SHEntry with the same doc identifier, the error
// page will persist.
mLSHE->SetUniqueDocIdentifier();
}
nsCAutoString url;
nsCAutoString charset;
if (aURI)
@@ -5714,13 +5732,13 @@ nsDocShell::EndPageLoad(nsIWebProgress * aProgress,
// We're done with the URI classifier for this channel
mClassifier = nsnull;
//
// Notify the ContentViewer that the Document has finished loading...
//
// This will cause any OnLoad(...) handlers to fire, if it is a HTML
// document...
//
// Notify the ContentViewer that the Document has finished loading. This
// will cause any OnLoad(...) and PopState(...) handlers to fire.
if (!mEODForCurrentDocument && mContentViewer) {
// Set the pending state object which will be returned to the page in
// the popstate event.
SetDocPendingStateObj(mLSHE);
mIsExecutingOnLoadHandler = PR_TRUE;
mContentViewer->LoadComplete(aStatus);
mIsExecutingOnLoadHandler = PR_FALSE;
@@ -7368,6 +7386,26 @@ nsDocShell::SetupNewViewer(nsIContentViewer * aNewViewer)
return NS_OK;
}
nsresult
nsDocShell::SetDocPendingStateObj(nsISHEntry *shEntry)
{
nsresult rv;
nsCOMPtr<nsIDocument> document = do_GetInterface(GetAsSupports(this));
NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
nsAutoString stateData;
if (shEntry) {
rv = shEntry->GetStateData(stateData);
NS_ENSURE_SUCCESS(rv, rv);
// if shEntry is null, we just set the pending state object to the
// empty string.
}
document->SetPendingStateObject(stateData);
return NS_OK;
}
nsresult
nsDocShell::CheckLoadingPermissions()
@@ -7844,27 +7882,50 @@ nsDocShell::InternalLoad(nsIURI * aURI,
}
#endif
}
if ((aLoadType == LOAD_NORMAL ||
aLoadType == LOAD_STOP_CONTENT ||
LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY) ||
aLoadType == LOAD_HISTORY ||
aLoadType == LOAD_LINK) && allowScroll) {
if (aLoadType == LOAD_NORMAL ||
aLoadType == LOAD_STOP_CONTENT ||
LOAD_TYPE_HAS_FLAGS(aLoadType, LOAD_FLAGS_REPLACE_HISTORY) ||
aLoadType == LOAD_HISTORY ||
aLoadType == LOAD_LINK) {
PRBool wasAnchor = PR_FALSE;
PRBool doHashchange = PR_FALSE;
nscoord cx, cy;
NS_ENSURE_SUCCESS(ScrollIfAnchor(aURI, &wasAnchor, aLoadType, &cx, &cy,
&doHashchange),
NS_ERROR_FAILURE);
if (wasAnchor) {
if (allowScroll) {
NS_ENSURE_SUCCESS(ScrollIfAnchor(aURI, &wasAnchor, aLoadType, &cx,
&cy, &doHashchange),
NS_ERROR_FAILURE);
}
// If this is a history load, aSHEntry will have document identifier X
// if it was created as a result of a History.pushState() from a
// SHEntry with doc ident X, or if it was created by changing the hash
// of the URI corresponding to a SHEntry with doc ident X.
PRBool sameDocIdent = PR_FALSE;
if (mOSHE && aSHEntry) {
PRUint64 ourDocIdent, otherDocIdent;
mOSHE->GetDocIdentifier(&ourDocIdent);
aSHEntry->GetDocIdentifier(&otherDocIdent);
sameDocIdent = (ourDocIdent == otherDocIdent);
}
// Do a short-circuited load if the new URI differs from the current
// URI only in the hash, or if the two entries belong to the same
// document and don't point to the same object.
//
// (If we didn't check that the SHEntries are different objects,
// history.go(0) would short-circuit instead of triggering a true
// load, and we wouldn't dispatch an onload event to the page.)
if (wasAnchor || (sameDocIdent && (mOSHE != aSHEntry))) {
mLoadType = aLoadType;
mURIResultedInDocument = PR_TRUE;
/* we need to assign mLSHE to aSHEntry right here, so that on History loads,
* SetCurrentURI() called from OnNewURI() will send proper
/* we need to assign mLSHE to aSHEntry right here, so that on History loads,
* SetCurrentURI() called from OnNewURI() will send proper
* onLocationChange() notifications to the browser to update
* back/forward buttons.
* back/forward buttons.
*/
SetHistoryEntry(&mLSHE, aSHEntry);
@@ -7877,10 +7938,11 @@ nsDocShell::InternalLoad(nsIURI * aURI,
mOSHE->GetOwner(getter_AddRefs(owner));
}
OnNewURI(aURI, nsnull, owner, mLoadType, PR_TRUE);
nsCOMPtr<nsIInputStream> postData;
PRUint32 pageIdent = PR_UINT32_MAX;
nsCOMPtr<nsISupports> cacheKey;
if (mOSHE) {
/* save current position of scroller(s) (bug 59774) */
mOSHE->SetScrollPosition(cx, cy);
@@ -7895,8 +7957,19 @@ nsDocShell::InternalLoad(nsIURI * aURI,
mOSHE->GetPageIdentifier(&pageIdent);
mOSHE->GetCacheKey(getter_AddRefs(cacheKey));
}
if (mLSHE && wasAnchor) {
// If it's an anchor load, set mLSHE's doc identifier to
// mOSHE's doc identifier -- These are the same documents,
// as far as HTML5 is concerned.
PRUint64 docIdent;
rv = mOSHE->GetDocIdentifier(&docIdent);
if (NS_SUCCEEDED(rv)) {
mLSHE->SetDocIdentifier(docIdent);
}
}
}
/* Assign mOSHE to mLSHE. This will either be a new entry created
* by OnNewURI() for normal loads or aSHEntry for history loads.
*/
@@ -7913,7 +7986,7 @@ nsDocShell::InternalLoad(nsIURI * aURI,
// cache first
if (cacheKey)
mOSHE->SetCacheKey(cacheKey);
// Propagate our page ident to the new mOSHE so that
// we'll know it just differed by a scroll on the page.
if (pageIdent != PR_UINT32_MAX)
@@ -7949,12 +8022,27 @@ nsDocShell::InternalLoad(nsIURI * aURI,
shEntry->SetTitle(mTitle);
}
if (doHashchange) {
nsCOMPtr<nsPIDOMWindow> window =
do_QueryInterface(mScriptGlobal);
if (sameDocIdent) {
// Set the doc's URI according to the new history entry's URI
nsCOMPtr<nsIURI> newURI;
mOSHE->GetURI(getter_AddRefs(newURI));
NS_ENSURE_TRUE(newURI, NS_ERROR_FAILURE);
nsCOMPtr<nsIDocument> doc =
do_GetInterface(GetAsSupports(this));
NS_ENSURE_TRUE(doc, NS_ERROR_FAILURE);
if (window)
window->DispatchSyncHashchange();
doc->SetDocumentURI(newURI);
}
SetDocPendingStateObj(mOSHE);
// Dispatch the popstate and hashchange events, as appropriate
nsCOMPtr<nsPIDOMWindow> window = do_QueryInterface(mScriptGlobal);
if (window) {
window->DispatchSyncPopState();
if (doHashchange)
window->DispatchSyncHashchange();
}
return NS_OK;
@@ -8837,6 +8925,14 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner,
if (uploadChannel) {
uploadChannel->GetUploadStream(getter_AddRefs(inputStream));
}
// If the response status indicates an error, unlink this session
// history entry from any entries sharing its doc ident.
PRUint32 responseStatus;
nsresult rv = httpChannel->GetResponseStatus(&responseStatus);
if (mLSHE && NS_SUCCEEDED(rv) && responseStatus >= 400) {
mLSHE->SetUniqueDocIdentifier();
}
}
}
/* Create SH Entry (mLSHE) only if there is a SessionHistory object (mSessionHistory) in
@@ -8858,7 +8954,7 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner,
aLoadType & LOAD_CMD_RELOAD)
updateHistory = PR_FALSE;
// Check if the url to be loaded is the same as the one already loaded.
// Check if the url to be loaded is the same as the one already loaded.
if (mCurrentURI)
aURI->Equals(mCurrentURI, &equalUri);
@@ -8895,7 +8991,6 @@ nsDocShell::OnNewURI(nsIURI * aURI, nsIChannel * aChannel, nsISupports* aOwner,
SetHistoryEntry(&mLSHE, mOSHE);
}
/* If the user pressed shift-reload, cache will create a new cache key
* for the page. Save the new cacheKey in Session History.
* see bug 90098
@@ -8985,7 +9080,283 @@ nsDocShell::SetReferrerURI(nsIURI * aURI)
//*****************************************************************************
// nsDocShell: Session History
//*****************************************************************************
//*****************************************************************************
nsresult
nsDocShell::StringifyJSValVariant(nsIVariant *aData, nsAString &aResult)
{
nsresult rv;
aResult.Truncate();
// First, try to extract a jsval from the variant |aData|. This works only
// if the variant implements GetAsJSVal.
jsval jsData;
rv = aData->GetAsJSVal(&jsData);
NS_ENSURE_SUCCESS(rv, NS_ERROR_UNEXPECTED);
// Now get the JSContext associated with the current document.
// First get the current document.
nsCOMPtr<nsIDocument> document = do_GetInterface(GetAsSupports(this));
NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
// Get the JSContext from the document, like we do in
// nsContentUtils::GetContextFromDocument().
nsIScriptGlobalObject *sgo = document->GetScopeObject();
NS_ENSURE_TRUE(sgo, NS_ERROR_FAILURE);
nsIScriptContext *scx = sgo->GetContext();
NS_ENSURE_TRUE(scx, NS_ERROR_FAILURE);
JSContext *cx = (JSContext *)scx->GetNativeContext();
// If our json call triggers a JS-to-C++ call, we want that call to use cx
// as the context. So we push cx onto the context stack.
nsCOMPtr<nsIJSContextStack> contextStack =
do_GetService("@mozilla.org/js/xpc/ContextStack;1", &rv);
NS_ENSURE_SUCCESS(rv, rv);
contextStack->Push(cx);
nsCOMPtr<nsIJSON> json = do_GetService("@mozilla.org/dom/json;1");
if(json) {
// Do the encoding
rv = json->EncodeFromJSVal(&jsData, cx, aResult);
}
else {
rv = NS_ERROR_FAILURE;
}
// Always pop the stack!
contextStack->Pop(&cx);
return rv;
}
NS_IMETHODIMP
nsDocShell::AddState(nsIVariant *aData, const nsAString& aTitle,
const nsAString& aURL, PRBool aReplace)
{
// Implements History.pushState and History.replaceState
// Here's what we do, roughly in the order specified by HTML5:
// 1. Serialize aData to JSON.
// 2. If the third argument is present,
// a. Resolve the url, relative to the first script's base URL
// b. If (a) fails, raise a SECURITY_ERR
// c. Compare the resulting absolute URL to the document's address. If
// any part of the URLs difer other than the <path>, <query>, and
// <fragment> components, raise a SECURITY_ERR and abort.
// 3. If !aReplace:
// Remove from the session history all entries after the current entry,
// as we would after a regular navigation.
// 4. As apropriate, either add a state object entry to the session history
// after the current entry with the following properties, or modify the
// current session history entry to set
// a. cloned data as the state object,
// b. the given title as the title, and,
// c. if the third argument was present, the absolute URL found in
// step 2
// 5. If aReplace is false (i.e. we're doing a pushState instead of a
// replaceState), notify bfcache that we've navigated to a new page.
// 6. If the third argument is present, set the document's current address
// to the absolute URL found in step 2.
//
// It's important that this function not run arbitrary scripts after step 1
// and before completing step 5. For example, if a script called
// history.back() before we completed step 5, bfcache might destroy an
// active content viewer. Since EvictContentViewers at the end of step 5
// might run script, we can't just put a script blocker around the critical
// section.
nsresult rv;
nsCOMPtr<nsIDocument> document = do_GetInterface(GetAsSupports(this));
NS_ENSURE_TRUE(document, NS_ERROR_FAILURE);
mLoadType = LOAD_PUSHSTATE;
// Step 1: Clone aData by getting its JSON representation
nsString dataStr;
rv = StringifyJSValVariant(aData, dataStr);
NS_ENSURE_SUCCESS(rv, rv);
// Check that the state object isn't too long.
// Default max length: 640k chars.
PRInt32 maxStateObjSize = 0xA0000;
if (mPrefs) {
mPrefs->GetIntPref("browser.history.maxStateObjectSize",
&maxStateObjSize);
}
if (maxStateObjSize < 0)
maxStateObjSize = 0;
NS_ENSURE_TRUE(dataStr.Length() <= (PRUint32)maxStateObjSize,
NS_ERROR_ILLEGAL_VALUE);
// Step 2: Resolve aURL
PRBool equalURIs = PR_TRUE;
nsCOMPtr<nsIURI> oldURI = mCurrentURI;
nsCOMPtr<nsIURI> newURI;
if (aURL.Length() == 0) {
newURI = mCurrentURI;
}
else {
// 2a: Resolve aURL relative to mURI
nsIURI* docBaseURI = document->GetBaseURI();
if (!docBaseURI)
return NS_ERROR_FAILURE;
nsCAutoString spec;
docBaseURI->GetSpec(spec);
nsCAutoString charset;
rv = docBaseURI->GetOriginCharset(charset);
NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE);
rv = NS_NewURI(getter_AddRefs(newURI), aURL,
charset.get(), docBaseURI);
// 2b: If 2a fails, raise a SECURITY_ERR
if (NS_FAILED(rv)) {
return NS_ERROR_DOM_SECURITY_ERR;
}
// 2c: Same-origin check.
if (!URIIsLocalFile(newURI)) {
// In addition to checking that the security manager says that
// the new URI has the same origin as our current URI, we also
// check that the two URIs have the same userpass. (The
// security manager says that |http://foo.com| and
// |http://me@foo.com| have the same origin.) mCurrentURI
// won't contain the password part of the userpass, so this
// means that it's never valid to specify a password in a
// pushState or replaceState URI.
nsCOMPtr<nsIScriptSecurityManager> secMan =
do_GetService(NS_SCRIPTSECURITYMANAGER_CONTRACTID);
NS_ENSURE_TRUE(secMan, NS_ERROR_FAILURE);
// It's very important that we check that newURI is of the same
// origin as mCurrentURI, not docBaseURI, because a page can
// set docBaseURI arbitrarily to any domain.
nsCAutoString currentUserPass, newUserPass;
NS_ENSURE_SUCCESS(mCurrentURI->GetUserPass(currentUserPass),
NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(newURI->GetUserPass(newUserPass),
NS_ERROR_FAILURE);
if (NS_FAILED(secMan->CheckSameOriginURI(mCurrentURI,
newURI, PR_TRUE)) ||
!currentUserPass.Equals(newUserPass)) {
return NS_ERROR_DOM_SECURITY_ERR;
}
}
else {
// It's a file:// URI
nsCOMPtr<nsIScriptObjectPrincipal> docScriptObj =
do_QueryInterface(document);
if (!docScriptObj) {
return NS_ERROR_DOM_SECURITY_ERR;
}
nsCOMPtr<nsIPrincipal> principal = docScriptObj->GetPrincipal();
if (!principal ||
NS_FAILED(principal->CheckMayLoad(newURI, PR_TRUE))) {
return NS_ERROR_DOM_SECURITY_ERR;
}
}
mCurrentURI->Equals(newURI, &equalURIs);
} // end of same-origin check
nsCOMPtr<nsISHistory> sessionHistory = mSessionHistory;
if (!sessionHistory) {
// Get the handle to SH from the root docshell
GetRootSessionHistory(getter_AddRefs(sessionHistory));
}
NS_ENSURE_TRUE(sessionHistory, NS_ERROR_FAILURE);
nsCOMPtr<nsISHistoryInternal> shInternal =
do_QueryInterface(sessionHistory, &rv);
NS_ENSURE_SUCCESS(rv, rv);
// Step 3: Create a new entry in the session history; this will erase
// all SHEntries after the new entry and make this entry the current
// one. This operation may modify mOSHE, which we need later, so we
// keep a reference here.
NS_ENSURE_TRUE(mOSHE, NS_ERROR_FAILURE);
nsCOMPtr<nsISHEntry> oldOSHE = mOSHE;
nsCOMPtr<nsISHEntry> newSHEntry;
if (!aReplace) {
rv = AddToSessionHistory(newURI, nsnull, nsnull,
getter_AddRefs(newSHEntry));
NS_ENSURE_SUCCESS(rv, rv);
NS_ENSURE_TRUE(newSHEntry, NS_ERROR_FAILURE);
// Set the new SHEntry's document identifier, if we can.
PRUint64 ourDocIdent;
NS_ENSURE_SUCCESS(oldOSHE->GetDocIdentifier(&ourDocIdent),
NS_ERROR_FAILURE);
NS_ENSURE_SUCCESS(newSHEntry->SetDocIdentifier(ourDocIdent),
NS_ERROR_FAILURE);
// AddToSessionHistory may not modify mOSHE. In case it doesn't,
// we'll just set mOSHE here.
mOSHE = newSHEntry;
} else {
newSHEntry = mOSHE;
newSHEntry->SetURI(newURI);
}
// Step 4: Modify new/original session history entry
newSHEntry->SetStateData(dataStr);
// Step 5: If aReplace is false, indicating that we're doing a pushState
// rather than a replaceState, notify bfcache that we've added a page to
// the history so it can evict content viewers if appropriate.
if (!aReplace) {
nsCOMPtr<nsISHistory> rootSH;
GetRootSessionHistory(getter_AddRefs(rootSH));
NS_ENSURE_TRUE(rootSH, NS_ERROR_UNEXPECTED);
nsCOMPtr<nsISHistoryInternal> internalSH =
do_QueryInterface(rootSH);
NS_ENSURE_TRUE(internalSH, NS_ERROR_UNEXPECTED);
PRInt32 curIndex = -1;
rv = rootSH->GetIndex(&curIndex);
if (NS_SUCCEEDED(rv) && curIndex > -1) {
internalSH->EvictContentViewers(curIndex - 1, curIndex);
}
}
// Step 6: If the document's URI changed, update document's URI and update
// global history
if (!equalURIs) {
SetCurrentURI(newURI, nsnull, PR_TRUE);
document->SetDocumentURI(newURI);
AddToGlobalHistory(newURI, PR_FALSE, oldURI);
}
// Try to set the title of the current history element
if (mOSHE)
mOSHE->SetTitle(aTitle);
// We need this to ensure that the back button is enabled after a
// pushState, if it wasn't already enabled.
FireOnLocationChange(this, nsnull, mCurrentURI);
return NS_OK;
}
PRBool
nsDocShell::ShouldAddToSessionHistory(nsIURI * aURI)
{
@@ -9428,7 +9799,6 @@ nsDocShell::CloneAndReplace(nsISHEntry *aSrcEntry,
return rv;
}
void
nsDocShell::SwapHistoryEntries(nsISHEntry *aOldEntry, nsISHEntry *aNewEntry)
{
@@ -9679,9 +10049,6 @@ nsresult
nsDocShell::AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
nsIChannel * aChannel)
{
if (mItemType != typeContent || !mGlobalHistory)
return NS_OK;
// 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));
@@ -9692,16 +10059,26 @@ nsDocShell::AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
return NS_OK;
}
nsCOMPtr<nsIURI> referrer;
if (aChannel)
NS_GetReferrerFromChannel(aChannel, getter_AddRefs(referrer));
return AddToGlobalHistory(aURI, aRedirect, referrer);
}
nsresult
nsDocShell::AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
nsIURI * aReferrer)
{
if (mItemType != typeContent || !mGlobalHistory)
return NS_OK;
PRBool visited;
nsresult rv = mGlobalHistory->IsVisited(aURI, &visited);
if (NS_FAILED(rv))
return rv;
nsCOMPtr<nsIURI> referrer;
if (aChannel)
NS_GetReferrerFromChannel(aChannel, getter_AddRefs(referrer));
rv = mGlobalHistory->AddURI(aURI, aRedirect, !IsFrame(), referrer);
rv = mGlobalHistory->AddURI(aURI, aRedirect, !IsFrame(), aReferrer);
if (NS_FAILED(rv))
return rv;
@@ -9714,6 +10091,7 @@ nsDocShell::AddToGlobalHistory(nsIURI * aURI, PRBool aRedirect,
}
return NS_OK;
}
//*****************************************************************************