зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1650257: Part 2 - Abort SetNewDocument() if ancestors are discarded/cached. r=nika,smaug,sg
Differential Revision: https://phabricator.services.mozilla.com/D87486
This commit is contained in:
Родитель
5f2d674982
Коммит
c2c6945169
|
@ -770,6 +770,25 @@ bool BrowsingContext::HasOpener() const {
|
|||
return sBrowsingContexts->Contains(GetOpenerId());
|
||||
}
|
||||
|
||||
bool BrowsingContext::AncestorsAreCurrent() const {
|
||||
const BrowsingContext* bc = this;
|
||||
while (true) {
|
||||
if (bc->IsDiscarded()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (WindowContext* wc = bc->GetParentWindowContext()) {
|
||||
if (wc->IsCached() || wc->IsDiscarded()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bc = wc->GetBrowsingContext();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Span<RefPtr<BrowsingContext>> BrowsingContext::Children() const {
|
||||
if (WindowContext* current = mCurrentWindowContext) {
|
||||
return current->Children();
|
||||
|
@ -1610,6 +1629,15 @@ void BrowsingContext::Location(JSContext* aCx,
|
|||
}
|
||||
}
|
||||
|
||||
bool BrowsingContext::RemoveRootFromBFCacheSync() {
|
||||
if (WindowContext* wc = GetParentWindowContext()) {
|
||||
if (RefPtr<Document> doc = wc->TopWindowContext()->GetDocument()) {
|
||||
return doc->RemoveFromBFCacheSync();
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
nsresult BrowsingContext::CheckSandboxFlags(nsDocShellLoadState* aLoadState) {
|
||||
const auto& sourceBC = aLoadState->SourceBrowsingContext();
|
||||
if (sourceBC.IsDiscarded() || (sourceBC && sourceBC->IsSandboxedFrom(this))) {
|
||||
|
|
|
@ -239,6 +239,10 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
|||
// message.
|
||||
bool IsDiscarded() const { return mIsDiscarded; }
|
||||
|
||||
// Returns true if none of the BrowsingContext's ancestor BrowsingContexts or
|
||||
// WindowContexts are discarded or cached.
|
||||
bool AncestorsAreCurrent() const;
|
||||
|
||||
bool Windowless() const { return mWindowless; }
|
||||
|
||||
// Get the DocShell for this BrowsingContext if it is in-process, or
|
||||
|
@ -293,6 +297,10 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
|||
|
||||
nsresult InternalLoad(nsDocShellLoadState* aLoadState);
|
||||
|
||||
// Removes the root document for this BrowsingContext tree from the BFCache,
|
||||
// if it is cached, and returns true if it was.
|
||||
bool RemoveRootFromBFCacheSync();
|
||||
|
||||
// If the load state includes a source BrowsingContext has been passed, check
|
||||
// to see if we are sandboxed from it as the result of an iframe or CSP
|
||||
// sandbox.
|
||||
|
|
|
@ -24,6 +24,8 @@
|
|||
#include "mozilla/NullPrincipal.h"
|
||||
#include "nsIWebNavigation.h"
|
||||
#include "mozilla/MozPromiseInlines.h"
|
||||
#include "nsDocShell.h"
|
||||
#include "nsFrameLoader.h"
|
||||
#include "nsGlobalWindowOuter.h"
|
||||
#include "nsIWebBrowserChrome.h"
|
||||
#include "nsNetUtil.h"
|
||||
|
@ -748,28 +750,6 @@ void CanonicalBrowsingContext::Stop(uint32_t aStopFlags) {
|
|||
}
|
||||
}
|
||||
|
||||
// While process switching, we need to check if any of our ancestors are
|
||||
// discarded or no longer current, in which case the process switch needs to be
|
||||
// aborted.
|
||||
static bool AncestorsAreCurrent(CanonicalBrowsingContext* aContext) {
|
||||
if (aContext->IsDiscarded()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<WindowGlobalParent> ancestorWindow(aContext->GetParentWindowContext());
|
||||
while (ancestorWindow) {
|
||||
// If our ancestor window is no longer the current window, or if any of our
|
||||
// ancestors have been discarded, return `false` to abort the process
|
||||
// switch.
|
||||
if (ancestorWindow->IsCached() || ancestorWindow->IsDiscarded() ||
|
||||
ancestorWindow->GetBrowsingContext()->IsDiscarded()) {
|
||||
return false;
|
||||
}
|
||||
ancestorWindow = ancestorWindow->GetParentWindowContext();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void CanonicalBrowsingContext::PendingRemotenessChange::ProcessReady() {
|
||||
if (!mPromise) {
|
||||
return;
|
||||
|
@ -798,7 +778,10 @@ void CanonicalBrowsingContext::PendingRemotenessChange::Finish() {
|
|||
return;
|
||||
}
|
||||
|
||||
if (!AncestorsAreCurrent(target)) {
|
||||
// While process switching, we need to check if any of our ancestors are
|
||||
// discarded or no longer current, in which case the process switch needs to be
|
||||
// aborted.
|
||||
if (!target->AncestorsAreCurrent()) {
|
||||
NS_WARNING("Ancestor context is no longer current");
|
||||
Cancel(NS_ERROR_FAILURE);
|
||||
return;
|
||||
|
@ -1054,7 +1037,7 @@ CanonicalBrowsingContext::ChangeRemoteness(const nsACString& aRemoteType,
|
|||
MOZ_DIAGNOSTIC_ASSERT(aSpecificGroupId == 0 || aReplaceBrowsingContext,
|
||||
"Cannot specify group ID unless replacing BC");
|
||||
|
||||
if (!AncestorsAreCurrent(this)) {
|
||||
if (!AncestorsAreCurrent()) {
|
||||
NS_WARNING("An ancestor context is no longer current");
|
||||
return RemotenessPromise::CreateAndReject(NS_ERROR_FAILURE, __func__);
|
||||
}
|
||||
|
|
|
@ -6398,6 +6398,11 @@ nsresult nsDocShell::CreateAboutBlankContentViewer(
|
|||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
if (!mBrowsingContext->AncestorsAreCurrent()) {
|
||||
mBrowsingContext->RemoveRootFromBFCacheSync();
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// mContentViewer->PermitUnload may release |this| docshell.
|
||||
nsCOMPtr<nsIDocShell> kungFuDeathGrip(this);
|
||||
|
||||
|
@ -7518,6 +7523,11 @@ nsresult nsDocShell::CreateContentViewer(const nsACString& aContentType,
|
|||
return NS_ERROR_DOCSHELL_DYING;
|
||||
}
|
||||
|
||||
if (!mBrowsingContext->AncestorsAreCurrent()) {
|
||||
mBrowsingContext->RemoveRootFromBFCacheSync();
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
// Can we check the content type of the current content viewer
|
||||
// and reuse it without destroying it and re-creating it?
|
||||
|
||||
|
|
|
@ -6355,6 +6355,14 @@ void Document::SetBFCacheEntry(nsIBFCacheEntry* aEntry) {
|
|||
mBFCacheEntry = aEntry;
|
||||
}
|
||||
|
||||
bool Document::RemoveFromBFCacheSync() {
|
||||
if (nsCOMPtr<nsIBFCacheEntry> entry = GetBFCacheEntry()) {
|
||||
entry->RemoveFromBFCacheSync();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void SubDocClearEntry(PLDHashTable* table, PLDHashEntryHdr* entry) {
|
||||
SubDocMapEntry* e = static_cast<SubDocMapEntry*>(entry);
|
||||
|
||||
|
|
|
@ -1156,6 +1156,10 @@ class Document : public nsINode,
|
|||
|
||||
nsIBFCacheEntry* GetBFCacheEntry() const { return mBFCacheEntry; }
|
||||
|
||||
// Removes this document from the BFCache, if it is cached, and returns
|
||||
// true if it was.
|
||||
bool RemoveFromBFCacheSync();
|
||||
|
||||
/**
|
||||
* Return the parent document of this document. Will return null
|
||||
* unless this document is within a compound document and has a
|
||||
|
|
|
@ -7418,6 +7418,13 @@ mozilla::dom::WindowContext* nsPIDOMWindowInner::GetWindowContext() const {
|
|||
return mWindowGlobalChild ? mWindowGlobalChild->WindowContext() : nullptr;
|
||||
}
|
||||
|
||||
bool nsPIDOMWindowInner::RemoveFromBFCacheSync() {
|
||||
if (Document* doc = GetExtantDoc()) {
|
||||
return doc->RemoveFromBFCacheSync();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void nsPIDOMWindowInner::MaybeCreateDoc() {
|
||||
// XXX: Forward to outer?
|
||||
MOZ_ASSERT(!mDoc);
|
||||
|
|
|
@ -2076,6 +2076,10 @@ nsresult nsGlobalWindowOuter::SetNewDocument(Document* aDocument,
|
|||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (!mBrowsingContext->AncestorsAreCurrent()) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
RefPtr<Document> oldDoc = mDoc;
|
||||
MOZ_RELEASE_ASSERT(oldDoc != aDocument);
|
||||
|
||||
|
|
|
@ -354,6 +354,10 @@ class nsPIDOMWindowInner : public mozIDOMWindow {
|
|||
return mWindowGlobalChild;
|
||||
}
|
||||
|
||||
// Removes this inner window from the BFCache, if it is cached, and returns
|
||||
// true if it was.
|
||||
bool RemoveFromBFCacheSync();
|
||||
|
||||
// Determine if the window is suspended or frozen. Outer windows
|
||||
// will forward this call to the inner window for convenience. If
|
||||
// there is no inner window then the outer window is considered
|
||||
|
|
|
@ -354,22 +354,9 @@ void BroadcastChannel::RemoveDocFromBFCache() {
|
|||
return;
|
||||
}
|
||||
|
||||
nsPIDOMWindowInner* window = GetOwner();
|
||||
if (!window) {
|
||||
return;
|
||||
if (nsPIDOMWindowInner* window = GetOwner()) {
|
||||
window->RemoveFromBFCacheSync();
|
||||
}
|
||||
|
||||
Document* doc = window->GetExtantDoc();
|
||||
if (!doc) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIBFCacheEntry> bfCacheEntry = doc->GetBFCacheEntry();
|
||||
if (!bfCacheEntry) {
|
||||
return;
|
||||
}
|
||||
|
||||
bfCacheEntry->RemoveFromBFCacheSync();
|
||||
}
|
||||
|
||||
void BroadcastChannel::DisconnectFromOwner() {
|
||||
|
|
|
@ -1786,11 +1786,8 @@ mozilla::ipc::IPCResult BackgroundDatabaseChild::RecvVersionChange(
|
|||
|
||||
// Anything in the bfcache has to be evicted and then we have to close the
|
||||
// database also.
|
||||
if (nsCOMPtr<Document> doc = owner->GetExtantDoc()) {
|
||||
if (nsCOMPtr<nsIBFCacheEntry> bfCacheEntry = doc->GetBFCacheEntry()) {
|
||||
bfCacheEntry->RemoveFromBFCacheSync();
|
||||
shouldAbortAndClose = true;
|
||||
}
|
||||
if (owner->RemoveFromBFCacheSync()) {
|
||||
shouldAbortAndClose = true;
|
||||
}
|
||||
|
||||
if (shouldAbortAndClose) {
|
||||
|
|
|
@ -834,22 +834,9 @@ void MessagePort::RemoveDocFromBFCache() {
|
|||
return;
|
||||
}
|
||||
|
||||
nsPIDOMWindowInner* window = GetOwner();
|
||||
if (!window) {
|
||||
return;
|
||||
if (nsPIDOMWindowInner* window = GetOwner()) {
|
||||
window->RemoveFromBFCacheSync();
|
||||
}
|
||||
|
||||
Document* doc = window->GetExtantDoc();
|
||||
if (!doc) {
|
||||
return;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIBFCacheEntry> bfCacheEntry = doc->GetBFCacheEntry();
|
||||
if (!bfCacheEntry) {
|
||||
return;
|
||||
}
|
||||
|
||||
bfCacheEntry->RemoveFromBFCacheSync();
|
||||
}
|
||||
|
||||
/* static */
|
||||
|
|
Загрузка…
Ссылка в новой задаче