diff --git a/docshell/shistory/nsISHEntry.idl b/docshell/shistory/nsISHEntry.idl index 2679cc735e96..d70d7a925bfd 100644 --- a/docshell/shistory/nsISHEntry.idl +++ b/docshell/shistory/nsISHEntry.idl @@ -335,9 +335,11 @@ interface nsISHEntry : nsISupports readonly attribute boolean loadedInThisProcess; /** - * Set the session history it belongs to. It's only set on root entries. + * The session history it belongs to. It's usually only set on root entries. + * SHEntry is strictly bound to the SHistory it belongs to; it should not be + * changed once set to a non-null value. */ - [noscript] void setSHistory(in nsISHistory aSHistory); + [noscript] attribute nsISHistory SHistory; }; [scriptable, uuid(bb66ac35-253b-471f-a317-3ece940f04c5)] diff --git a/docshell/shistory/nsSHEntry.cpp b/docshell/shistory/nsSHEntry.cpp index 087e9c1869f7..200fdc534523 100644 --- a/docshell/shistory/nsSHEntry.cpp +++ b/docshell/shistory/nsSHEntry.cpp @@ -974,6 +974,14 @@ nsSHEntry::SetLastTouched(uint32_t aLastTouched) return NS_OK; } +NS_IMETHODIMP +nsSHEntry::GetSHistory(nsISHistory** aSHistory) +{ + nsCOMPtr shistory(do_QueryReferent(mShared->mSHistory)); + shistory.forget(aSHistory); + return NS_OK; +} + NS_IMETHODIMP nsSHEntry::SetSHistory(nsISHistory* aSHistory) { diff --git a/docshell/shistory/nsSHistory.cpp b/docshell/shistory/nsSHistory.cpp index 02cecf9da295..72513f843fb6 100644 --- a/docshell/shistory/nsSHistory.cpp +++ b/docshell/shistory/nsSHistory.cpp @@ -385,6 +385,15 @@ nsSHistory::AddEntry(nsISHEntry* aSHEntry, bool aPersist) { NS_ENSURE_ARG(aSHEntry); + nsCOMPtr shistoryOfEntry; + aSHEntry->GetSHistory(getter_AddRefs(shistoryOfEntry)); + if (shistoryOfEntry && shistoryOfEntry != this) { + NS_WARNING("The entry has been associated to another nsISHistory instance. " + "Try nsISHEntry.clone() and nsISHEntry.abandonBFCacheEntry() " + "first if you're copying an entry from another nsISHistory."); + return NS_ERROR_FAILURE; + } + aSHEntry->SetSHistory(this); // If we have a root docshell, update the docshell id of the root shentry to @@ -867,6 +876,17 @@ nsSHistory::ReplaceEntry(int32_t aIndex, nsISHEntry* aReplaceEntry) rv = GetTransactionAtIndex(aIndex, getter_AddRefs(currentTxn)); if (currentTxn) { + nsCOMPtr shistoryOfEntry; + aReplaceEntry->GetSHistory(getter_AddRefs(shistoryOfEntry)); + if (shistoryOfEntry && shistoryOfEntry != this) { + NS_WARNING("The entry has been associated to another nsISHistory instance. " + "Try nsISHEntry.clone() and nsISHEntry.abandonBFCacheEntry() " + "first if you're copying an entry from another nsISHistory."); + return NS_ERROR_FAILURE; + } + + aReplaceEntry->SetSHistory(this); + NOTIFY_LISTENERS(OnHistoryReplaceEntry, (aIndex)); // Set the replacement entry in the transaction @@ -1938,6 +1958,14 @@ nsSHistory::SetRootDocShell(nsIDocShell* aDocShell) return NS_ERROR_UNEXPECTED; } + // Seamonkey moves shistory between s when restoring a tab. + // Let's try not to break our friend too badly... + if (mHistoryTracker) { + NS_WARNING("Change the root docshell of a shistory is unsafe and " + "potentially problematic."); + mHistoryTracker->AgeAllGenerations(); + } + RefPtr tabGroup = win->TabGroup(); mHistoryTracker = mozilla::MakeUnique( this,