Bug 1921972 - Allow to propagate loadgroup flags to parent process. r=nika,necko-reviewers,valentin
As per discussion. Test is in the other patch, assuming this is green I'll incorporate it, but gotta go for the day. Differential Revision: https://phabricator.services.mozilla.com/D224824
This commit is contained in:
@@ -1074,10 +1074,8 @@ nsresult nsLoadGroup::MergeLoadFlags(nsIRequest* aRequest,
|
|||||||
|
|
||||||
oldFlags = flags;
|
oldFlags = flags;
|
||||||
|
|
||||||
// Inherit the following bits...
|
// Inherit some bits...
|
||||||
flags |= (mLoadFlags &
|
flags |= mLoadFlags & kInheritedLoadFlags;
|
||||||
(LOAD_BACKGROUND | LOAD_BYPASS_CACHE | LOAD_FROM_CACHE |
|
|
||||||
VALIDATE_ALWAYS | VALIDATE_ONCE_PER_SESSION | VALIDATE_NEVER));
|
|
||||||
|
|
||||||
// ... and force the default flags.
|
// ... and force the default flags.
|
||||||
flags |= mDefaultLoadFlags;
|
flags |= mDefaultLoadFlags;
|
||||||
|
|||||||
@@ -61,6 +61,18 @@ class nsLoadGroup : public nsILoadGroup,
|
|||||||
void SetGroupObserver(nsIRequestObserver* aObserver,
|
void SetGroupObserver(nsIRequestObserver* aObserver,
|
||||||
bool aIncludeBackgroundRequests);
|
bool aIncludeBackgroundRequests);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flags inherited from the default request in the load group onto other loads
|
||||||
|
* added to the load group.
|
||||||
|
*
|
||||||
|
* NOTE(emilio): If modifying these, be aware that we allow these flags to be
|
||||||
|
* effectively set from the content process on a document navigation, and
|
||||||
|
* thus nothing security-critical should be allowed here.
|
||||||
|
*/
|
||||||
|
static constexpr nsLoadFlags kInheritedLoadFlags =
|
||||||
|
LOAD_BACKGROUND | LOAD_BYPASS_CACHE | LOAD_FROM_CACHE | VALIDATE_ALWAYS |
|
||||||
|
VALIDATE_ONCE_PER_SESSION | VALIDATE_NEVER;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual ~nsLoadGroup();
|
virtual ~nsLoadGroup();
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
#include "nsILoadInfo.h"
|
#include "nsILoadInfo.h"
|
||||||
#include "nsIStreamListener.h"
|
#include "nsIStreamListener.h"
|
||||||
#include "nsIURI.h"
|
#include "nsIURI.h"
|
||||||
|
#include "nsLoadGroup.h"
|
||||||
#include "nsMimeTypes.h"
|
#include "nsMimeTypes.h"
|
||||||
#include "nsNetUtil.h"
|
#include "nsNetUtil.h"
|
||||||
#include "nsPIDOMWindow.h"
|
#include "nsPIDOMWindow.h"
|
||||||
@@ -294,25 +295,30 @@ DocumentChannel::SetTRRMode(nsIRequest::TRRMode aTRRMode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP DocumentChannel::SetLoadFlags(nsLoadFlags aLoadFlags) {
|
NS_IMETHODIMP DocumentChannel::SetLoadFlags(nsLoadFlags aLoadFlags) {
|
||||||
// Setting load flags for TYPE_OBJECT is OK, so long as the channel to parent
|
nsLoadFlags mayChange = 0;
|
||||||
// isn't opened yet, or we're only setting the `LOAD_DOCUMENT_URI` flag.
|
if (mLoadInfo->GetExternalContentPolicyType() ==
|
||||||
auto contentPolicy = mLoadInfo->GetExternalContentPolicyType();
|
ExtContentPolicy::TYPE_OBJECT) {
|
||||||
if (contentPolicy == ExtContentPolicy::TYPE_OBJECT) {
|
// Setting load flags for TYPE_OBJECT is OK, so long as the channel to
|
||||||
if (mWasOpened) {
|
// parent isn't opened yet, or we're only setting the `LOAD_DOCUMENT_URI`
|
||||||
MOZ_DIAGNOSTIC_ASSERT(
|
// flag.
|
||||||
aLoadFlags == (mLoadFlags | nsIChannel::LOAD_DOCUMENT_URI),
|
mayChange = mWasOpened ? LOAD_DOCUMENT_URI : ~0u;
|
||||||
"After the channel has been opened, can only set the "
|
} else if (!mWasOpened) {
|
||||||
"`LOAD_DOCUMENT_URI` flag.");
|
// If we haven't been opened yet, allow the LoadGroup to
|
||||||
}
|
// set cache control flags inherited from the default channel.
|
||||||
|
mayChange = nsLoadGroup::kInheritedLoadFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we're allowed to adjust these flags.
|
||||||
|
if ((mLoadFlags & ~mayChange) == (aLoadFlags & ~mayChange)) {
|
||||||
mLoadFlags = aLoadFlags;
|
mLoadFlags = aLoadFlags;
|
||||||
return NS_OK;
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
MOZ_CRASH_UNSAFE_PRINTF(
|
MOZ_CRASH_UNSAFE_PRINTF(
|
||||||
"DocumentChannel::SetLoadFlags: Don't set flags after creation "
|
"DocumentChannel::SetLoadFlags: Don't set flags after creation "
|
||||||
"(differing flags %x != %x)",
|
"(differing flags %x != %x)",
|
||||||
(mLoadFlags ^ aLoadFlags) & mLoadFlags,
|
(mLoadFlags ^ aLoadFlags) & mLoadFlags,
|
||||||
(mLoadFlags ^ aLoadFlags) & aLoadFlags);
|
(mLoadFlags ^ aLoadFlags) & aLoadFlags);
|
||||||
|
return NS_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
NS_IMETHODIMP DocumentChannel::GetOriginalURI(nsIURI** aOriginalURI) {
|
NS_IMETHODIMP DocumentChannel::GetOriginalURI(nsIURI** aOriginalURI) {
|
||||||
|
|||||||
@@ -119,6 +119,7 @@ DocumentChannelChild::AsyncOpen(nsIStreamListener* aListener) {
|
|||||||
case ExtContentPolicy::TYPE_DOCUMENT:
|
case ExtContentPolicy::TYPE_DOCUMENT:
|
||||||
case ExtContentPolicy::TYPE_SUBDOCUMENT: {
|
case ExtContentPolicy::TYPE_SUBDOCUMENT: {
|
||||||
DocumentCreationArgs docArgs;
|
DocumentCreationArgs docArgs;
|
||||||
|
docArgs.loadFlags() = mLoadFlags;
|
||||||
docArgs.uriModified() = mUriModified;
|
docArgs.uriModified() = mUriModified;
|
||||||
docArgs.isEmbeddingBlockedError() = mIsEmbeddingBlockedError;
|
docArgs.isEmbeddingBlockedError() = mIsEmbeddingBlockedError;
|
||||||
|
|
||||||
|
|||||||
@@ -67,10 +67,10 @@ bool DocumentChannelParent::Init(dom::CanonicalBrowsingContext* aContext,
|
|||||||
const DocumentCreationArgs& docArgs = aArgs.elementCreationArgs();
|
const DocumentCreationArgs& docArgs = aArgs.elementCreationArgs();
|
||||||
|
|
||||||
promise = mDocumentLoadListener->OpenDocument(
|
promise = mDocumentLoadListener->OpenDocument(
|
||||||
loadState, aArgs.cacheKey(), Some(aArgs.channelId()),
|
loadState, docArgs.loadFlags(), aArgs.cacheKey(),
|
||||||
aArgs.asyncOpenTime(), aArgs.timing(), std::move(clientInfo),
|
Some(aArgs.channelId()), aArgs.asyncOpenTime(), aArgs.timing(),
|
||||||
docArgs.uriModified(), Some(docArgs.isEmbeddingBlockedError()),
|
std::move(clientInfo), docArgs.uriModified(),
|
||||||
contentParent, &rv);
|
Some(docArgs.isEmbeddingBlockedError()), contentParent, &rv);
|
||||||
} else {
|
} else {
|
||||||
const ObjectCreationArgs& objectArgs = aArgs.elementCreationArgs();
|
const ObjectCreationArgs& objectArgs = aArgs.elementCreationArgs();
|
||||||
|
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "DocumentLoadListener.h"
|
#include "DocumentLoadListener.h"
|
||||||
|
|
||||||
#include "NeckoCommon.h"
|
#include "NeckoCommon.h"
|
||||||
|
#include "nsLoadGroup.h"
|
||||||
#include "mozilla/AntiTrackingUtils.h"
|
#include "mozilla/AntiTrackingUtils.h"
|
||||||
#include "mozilla/DebugOnly.h"
|
#include "mozilla/DebugOnly.h"
|
||||||
#include "mozilla/Components.h"
|
#include "mozilla/Components.h"
|
||||||
@@ -964,7 +965,7 @@ auto DocumentLoadListener::Open(nsDocShellLoadState* aLoadState,
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto DocumentLoadListener::OpenDocument(
|
auto DocumentLoadListener::OpenDocument(
|
||||||
nsDocShellLoadState* aLoadState, uint32_t aCacheKey,
|
nsDocShellLoadState* aLoadState, nsLoadFlags aLoadFlags, uint32_t aCacheKey,
|
||||||
const Maybe<uint64_t>& aChannelId, const TimeStamp& aAsyncOpenTime,
|
const Maybe<uint64_t>& aChannelId, const TimeStamp& aAsyncOpenTime,
|
||||||
nsDOMNavigationTiming* aTiming, Maybe<dom::ClientInfo>&& aInfo,
|
nsDOMNavigationTiming* aTiming, Maybe<dom::ClientInfo>&& aInfo,
|
||||||
bool aUriModified, Maybe<bool> aIsEmbeddingBlockedError,
|
bool aUriModified, Maybe<bool> aIsEmbeddingBlockedError,
|
||||||
@@ -977,15 +978,32 @@ auto DocumentLoadListener::OpenDocument(
|
|||||||
RefPtr<CanonicalBrowsingContext> browsingContext =
|
RefPtr<CanonicalBrowsingContext> browsingContext =
|
||||||
GetDocumentBrowsingContext();
|
GetDocumentBrowsingContext();
|
||||||
|
|
||||||
|
// As a security check, check that aLoadFlags matches what we expect. We
|
||||||
|
// expect them to be the same we compute on the parent, except for the load
|
||||||
|
// group flags.
|
||||||
|
{
|
||||||
|
const nsLoadFlags parentLoadFlags = aLoadState->CalculateChannelLoadFlags(
|
||||||
|
browsingContext, aUriModified, std::move(aIsEmbeddingBlockedError));
|
||||||
|
const nsLoadFlags differing = parentLoadFlags ^ aLoadFlags;
|
||||||
|
if (differing & ~nsLoadGroup::kInheritedLoadFlags) {
|
||||||
|
#ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED
|
||||||
|
MOZ_CRASH_UNSAFE_PRINTF(
|
||||||
|
"DocumentLoadListener::OpenDocument: Unexpected load flags: "
|
||||||
|
"%x vs. %x (differing %x vs. %x)",
|
||||||
|
parentLoadFlags, aLoadFlags, differing & parentLoadFlags,
|
||||||
|
differing & aLoadFlags);
|
||||||
|
#endif
|
||||||
|
*aRv = NS_ERROR_UNEXPECTED;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// If this is a top-level load, then rebuild the LoadInfo from scratch,
|
// If this is a top-level load, then rebuild the LoadInfo from scratch,
|
||||||
// since the goal is to be able to initiate loads in the parent, where the
|
// since the goal is to be able to initiate loads in the parent, where the
|
||||||
// content process won't have provided us with an existing one.
|
// content process won't have provided us with an existing one.
|
||||||
RefPtr<LoadInfo> loadInfo =
|
RefPtr<LoadInfo> loadInfo =
|
||||||
CreateDocumentLoadInfo(browsingContext, aLoadState);
|
CreateDocumentLoadInfo(browsingContext, aLoadState);
|
||||||
|
|
||||||
nsLoadFlags loadFlags = aLoadState->CalculateChannelLoadFlags(
|
|
||||||
browsingContext, aUriModified, std::move(aIsEmbeddingBlockedError));
|
|
||||||
|
|
||||||
// Keep track of navigation for the Bounce Tracking Protection.
|
// Keep track of navigation for the Bounce Tracking Protection.
|
||||||
if (browsingContext->IsTopContent()) {
|
if (browsingContext->IsTopContent()) {
|
||||||
RefPtr<BounceTrackingState> bounceTrackingState =
|
RefPtr<BounceTrackingState> bounceTrackingState =
|
||||||
@@ -1007,7 +1025,7 @@ auto DocumentLoadListener::OpenDocument(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Open(aLoadState, loadInfo, loadFlags, aCacheKey, aChannelId,
|
return Open(aLoadState, loadInfo, aLoadFlags, aCacheKey, aChannelId,
|
||||||
aAsyncOpenTime, aTiming, std::move(aInfo), false, aContentParent,
|
aAsyncOpenTime, aTiming, std::move(aInfo), false, aContentParent,
|
||||||
aRv);
|
aRv);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -160,11 +160,12 @@ class DocumentLoadListener : public nsIInterfaceRequestor,
|
|||||||
|
|
||||||
public:
|
public:
|
||||||
RefPtr<OpenPromise> OpenDocument(
|
RefPtr<OpenPromise> OpenDocument(
|
||||||
nsDocShellLoadState* aLoadState, uint32_t aCacheKey,
|
nsDocShellLoadState* aLoadState, nsLoadFlags aLoadFlags,
|
||||||
const Maybe<uint64_t>& aChannelId, const TimeStamp& aAsyncOpenTime,
|
uint32_t aCacheKey, const Maybe<uint64_t>& aChannelId,
|
||||||
nsDOMNavigationTiming* aTiming, Maybe<dom::ClientInfo>&& aInfo,
|
const TimeStamp& aAsyncOpenTime, nsDOMNavigationTiming* aTiming,
|
||||||
bool aUriModified, Maybe<bool> aIsEmbeddingBlockedError,
|
Maybe<dom::ClientInfo>&& aInfo, bool aUriModified,
|
||||||
dom::ContentParent* aContentParent, nsresult* aRv);
|
Maybe<bool> aIsEmbeddingBlockedError, dom::ContentParent* aContentParent,
|
||||||
|
nsresult* aRv);
|
||||||
|
|
||||||
RefPtr<OpenPromise> OpenObject(
|
RefPtr<OpenPromise> OpenObject(
|
||||||
nsDocShellLoadState* aLoadState, uint32_t aCacheKey,
|
nsDocShellLoadState* aLoadState, uint32_t aCacheKey,
|
||||||
|
|||||||
@@ -481,13 +481,14 @@ struct CookieStructTable
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct DocumentCreationArgs {
|
struct DocumentCreationArgs {
|
||||||
|
uint32_t loadFlags;
|
||||||
bool uriModified;
|
bool uriModified;
|
||||||
bool isEmbeddingBlockedError;
|
bool isEmbeddingBlockedError;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ObjectCreationArgs {
|
struct ObjectCreationArgs {
|
||||||
uint64_t embedderInnerWindowId;
|
|
||||||
uint32_t loadFlags;
|
uint32_t loadFlags;
|
||||||
|
uint64_t embedderInnerWindowId;
|
||||||
nsContentPolicyType contentPolicyType;
|
nsContentPolicyType contentPolicyType;
|
||||||
bool isUrgentStart;
|
bool isUrgentStart;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -175,8 +175,8 @@ NS_IMETHODIMP ParentProcessDocumentChannel::AsyncOpen(
|
|||||||
RefPtr<DocumentLoadListener::OpenPromise> promise;
|
RefPtr<DocumentLoadListener::OpenPromise> promise;
|
||||||
if (isDocumentLoad) {
|
if (isDocumentLoad) {
|
||||||
promise = mDocumentLoadListener->OpenDocument(
|
promise = mDocumentLoadListener->OpenDocument(
|
||||||
mLoadState, mCacheKey, Some(mChannelId), TimeStamp::Now(), mTiming,
|
mLoadState, mLoadFlags, mCacheKey, Some(mChannelId), TimeStamp::Now(),
|
||||||
std::move(initialClientInfo), mUriModified,
|
mTiming, std::move(initialClientInfo), mUriModified,
|
||||||
Some(mIsEmbeddingBlockedError), nullptr /* ContentParent */, &rv);
|
Some(mIsEmbeddingBlockedError), nullptr /* ContentParent */, &rv);
|
||||||
} else {
|
} else {
|
||||||
promise = mDocumentLoadListener->OpenObject(
|
promise = mDocumentLoadListener->OpenObject(
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<script>
|
||||||
|
(async function() {
|
||||||
|
if (!location.hash) {
|
||||||
|
await new Promise(r => {
|
||||||
|
window.addEventListener("hashchange", r, { once: true });
|
||||||
|
location.hash = "foo";
|
||||||
|
});
|
||||||
|
location.reload(true);
|
||||||
|
} else {
|
||||||
|
location.href = "unlikely-protocol://foo"
|
||||||
|
parent.document.documentElement.classList = "";
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
<!doctype html>
|
||||||
|
<html class="test-wait">
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<link rel="help" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1921972">
|
||||||
|
<link rel="author" title="Emilio Cobos Álvarez" href="mailto:emilio@crisal.io">
|
||||||
|
<link rel="author" title="Mozilla" href="https://mozilla.org">
|
||||||
|
<!-- frame removes test-wait -->
|
||||||
|
<iframe src="resources/unknown-protocol-reload-crash-frame.html"></iframe>
|
||||||
|
</html>
|
||||||
Reference in New Issue
Block a user