Bug 1721217 - Part 2: Fix the race between navigations originating in the parent and in the content, r=nika
Add a synced ParentInitiatedNavigationEpoch field to browsing context, which only gets incremented when we start navigations in the parent process. When a child process initiates a navigation, it sends the current value of the field that it sees via DocumentChannelCreationArgs. In the parent process, we can compare the value of that field with the latest one for the same browsing context. If the latest value is higher than the one provided by the content process, it means that in the meantime parent process has started a navigation so the earlier navigation originating in the content process will be cancelled. Differential Revision: https://phabricator.services.mozilla.com/D126842
This commit is contained in:
@@ -3182,6 +3182,11 @@ auto BrowsingContext::CanSet(FieldIndex<IDX_CurrentInnerWindowId>,
|
||||
return CanSetResult::Allow;
|
||||
}
|
||||
|
||||
bool BrowsingContext::CanSet(FieldIndex<IDX_ParentInitiatedNavigationEpoch>,
|
||||
const uint64_t& aValue, ContentParent* aSource) {
|
||||
return XRE_IsParentProcess() && !aSource;
|
||||
}
|
||||
|
||||
void BrowsingContext::DidSet(FieldIndex<IDX_CurrentInnerWindowId>) {
|
||||
RefPtr<WindowContext> prevWindowContext = mCurrentWindowContext.forget();
|
||||
mCurrentWindowContext = WindowContext::GetById(GetCurrentInnerWindowId());
|
||||
|
||||
@@ -221,7 +221,11 @@ enum class ExplicitActiveStatus : uint8_t {
|
||||
/* The count of request that are used to prevent the browsing context tree \
|
||||
* from being suspended, which would ONLY be modified on the top level \
|
||||
* context in the chrome process because that's a non-atomic counter */ \
|
||||
FIELD(PageAwakeRequestCount, uint32_t)
|
||||
FIELD(PageAwakeRequestCount, uint32_t) \
|
||||
/* This field only gets incrememented when we start navigations in the \
|
||||
* parent process. This is used for keeping track of the racing navigations \
|
||||
* between the parent and content processes. */ \
|
||||
FIELD(ParentInitiatedNavigationEpoch, uint64_t)
|
||||
|
||||
// BrowsingContext, in this context, is the cross process replicated
|
||||
// environment in which information about documents is stored. In
|
||||
@@ -1051,6 +1055,9 @@ class BrowsingContext : public nsILoadContext, public nsWrapperCache {
|
||||
|
||||
void DidSet(FieldIndex<IDX_CurrentInnerWindowId>);
|
||||
|
||||
bool CanSet(FieldIndex<IDX_ParentInitiatedNavigationEpoch>,
|
||||
const uint64_t& aValue, ContentParent* aSource);
|
||||
|
||||
bool CanSet(FieldIndex<IDX_IsPopupSpam>, const bool& aValue,
|
||||
ContentParent* aSource);
|
||||
|
||||
|
||||
@@ -70,6 +70,9 @@ static mozilla::LazyLogModule sPBContext("PBContext");
|
||||
// Global count of canonical browsing contexts with the private attribute set
|
||||
static uint32_t gNumberOfPrivateContexts = 0;
|
||||
|
||||
// Current parent process epoch for parent initiated navigations
|
||||
static uint64_t gParentInitiatedNavigationEpoch = 0;
|
||||
|
||||
static void IncreasePrivateCount() {
|
||||
gNumberOfPrivateContexts++;
|
||||
MOZ_LOG(sPBContext, mozilla::LogLevel::Debug,
|
||||
@@ -2043,6 +2046,8 @@ bool CanonicalBrowsingContext::LoadInParent(nsDocShellLoadState* aLoadState,
|
||||
|
||||
MOZ_ASSERT(!net::SchemeIsJavascript(aLoadState->URI()));
|
||||
|
||||
MOZ_ALWAYS_SUCCEEDS(
|
||||
SetParentInitiatedNavigationEpoch(++gParentInitiatedNavigationEpoch));
|
||||
// Note: If successful, this will recurse into StartDocumentLoad and
|
||||
// set mCurrentLoad to the DocumentLoadListener instance created.
|
||||
// Ideally in the future we will only start loads from here, and we can
|
||||
|
||||
@@ -113,6 +113,8 @@ DocumentChannelChild::AsyncOpen(nsIStreamListener* aListener) {
|
||||
args.cacheKey() = mCacheKey;
|
||||
args.channelId() = mChannelId;
|
||||
args.asyncOpenTime() = TimeStamp::Now();
|
||||
args.parentInitiatedNavigationEpoch() =
|
||||
loadingContext->GetParentInitiatedNavigationEpoch();
|
||||
|
||||
Maybe<IPCClientInfo> ipcClientInfo;
|
||||
if (mInitialClientInfo.isSome()) {
|
||||
|
||||
@@ -35,6 +35,11 @@ bool DocumentChannelParent::Init(dom::CanonicalBrowsingContext* aContext,
|
||||
new nsDocShellLoadState(aArgs.loadState());
|
||||
LOG(("DocumentChannelParent Init [this=%p, uri=%s]", this,
|
||||
loadState->URI()->GetSpecOrDefault().get()));
|
||||
if (aArgs.parentInitiatedNavigationEpoch() <
|
||||
aContext->GetParentInitiatedNavigationEpoch()) {
|
||||
nsresult rv = NS_BINDING_ABORTED;
|
||||
return SendFailedAsyncOpen(rv);
|
||||
}
|
||||
|
||||
ContentParent* contentParent =
|
||||
static_cast<ContentParent*>(Manager()->Manager());
|
||||
|
||||
@@ -440,6 +440,7 @@ struct DocumentChannelCreationArgs {
|
||||
nsDOMNavigationTiming? timing;
|
||||
IPCClientInfo? initialClientInfo;
|
||||
DocumentChannelElementCreationArgs elementCreationArgs;
|
||||
uint64_t parentInitiatedNavigationEpoch;
|
||||
};
|
||||
|
||||
struct RedirectToRealChannelArgs {
|
||||
|
||||
Reference in New Issue
Block a user