Bug 1921733 - Update load info when object loads get upgraded. r=necko-reviewers,peterv

Differential Revision: https://phabricator.services.mozilla.com/D224956
This commit is contained in:
Andreas Farre 2024-10-15 09:12:17 +00:00
parent 3f3edff318
commit 01fc6bda19
5 changed files with 100 additions and 7 deletions

View File

@ -218,8 +218,6 @@ already_AddRefed<nsIDocShell> nsObjectLoadingContent::SetupDocShell(
return nullptr;
}
MaybeStoreCrossOriginFeaturePolicy();
return docShell.forget();
}
@ -1554,6 +1552,7 @@ void nsObjectLoadingContent::Destroy() {
void nsObjectLoadingContent::Traverse(nsObjectLoadingContent* tmp,
nsCycleCollectionTraversalCallback& cb) {
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFrameLoader);
NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFeaturePolicy);
}
/* static */
@ -1562,6 +1561,7 @@ void nsObjectLoadingContent::Unlink(nsObjectLoadingContent* tmp) {
tmp->mFrameLoader->Destroy();
}
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFrameLoader);
NS_IMPL_CYCLE_COLLECTION_UNLINK(mFeaturePolicy);
}
void nsObjectLoadingContent::UnloadObject(bool aResetState) {
@ -1720,6 +1720,13 @@ nsObjectLoadingContent::UpgradeLoadToDocument(
return NS_ERROR_FAILURE;
}
// At this point we know that we have a browsing context, so it's time to make
// sure that that browsing context gets the correct container feature policy.
// This is needed for `DocumentLoadListener::MaybeTriggerProcessSwitch` to be
// able to start loading the document with the correct container feature
// policy in the load info.
RefreshFeaturePolicy();
bc.forget(aBrowsingContext);
return NS_OK;
}
@ -1818,6 +1825,9 @@ void nsObjectLoadingContent::SubdocumentImageLoadComplete(nsresult aResult) {
void nsObjectLoadingContent::MaybeStoreCrossOriginFeaturePolicy() {
MOZ_DIAGNOSTIC_ASSERT(mFrameLoader);
if (!mFrameLoader) {
return;
}
// If the browsingContext is not ready (because docshell is dead), don't try
// to create one.
@ -1831,15 +1841,54 @@ void nsObjectLoadingContent::MaybeStoreCrossOriginFeaturePolicy() {
return;
}
Element* el = AsElement();
auto* el = nsGenericHTMLElement::FromNode(AsElement());
if (!el->IsInComposedDoc()) {
return;
}
FeaturePolicy* featurePolicy = el->OwnerDoc()->FeaturePolicy();
if (ContentChild* cc = ContentChild::GetSingleton(); cc && featurePolicy) {
if (ContentChild* cc = ContentChild::GetSingleton()) {
Unused << cc->SendSetContainerFeaturePolicy(
browsingContext, Some(featurePolicy->ToFeaturePolicyInfo()));
browsingContext, Some(mFeaturePolicy->ToFeaturePolicyInfo()));
}
}
/* static */ already_AddRefed<nsIPrincipal>
nsObjectLoadingContent::GetFeaturePolicyDefaultOrigin(nsINode* aNode) {
auto* el = nsGenericHTMLElement::FromNode(aNode);
nsCOMPtr<nsIURI> nodeURI;
// Different elements keep this in various locations
if (el->NodeInfo()->Equals(nsGkAtoms::object)) {
el->GetURIAttr(nsGkAtoms::data, nullptr, getter_AddRefs(nodeURI));
} else if (el->NodeInfo()->Equals(nsGkAtoms::embed)) {
el->GetURIAttr(nsGkAtoms::src, nullptr, getter_AddRefs(nodeURI));
}
nsCOMPtr<nsIPrincipal> principal;
if (nodeURI) {
principal = BasePrincipal::CreateContentPrincipal(
nodeURI,
BasePrincipal::Cast(el->NodePrincipal())->OriginAttributesRef());
} else {
principal = el->NodePrincipal();
}
return principal.forget();
}
void nsObjectLoadingContent::RefreshFeaturePolicy() {
if (mType != ObjectType::Document) {
return;
}
if (!mFeaturePolicy) {
mFeaturePolicy = MakeAndAddRef<FeaturePolicy>(AsElement());
}
// The origin can change if 'src' or 'data' attributes change.
nsCOMPtr<nsIPrincipal> origin = GetFeaturePolicyDefaultOrigin(AsElement());
MOZ_ASSERT(origin);
mFeaturePolicy->SetDefaultOrigin(origin);
mFeaturePolicy->InheritPolicy(AsElement()->OwnerDoc()->FeaturePolicy());
MaybeStoreCrossOriginFeaturePolicy();
}

View File

@ -27,6 +27,7 @@ class nsFrameLoader;
namespace mozilla::dom {
struct BindContext;
class FeaturePolicy;
template <typename T>
class Sequence;
class HTMLIFrameElement;
@ -213,6 +214,14 @@ class nsObjectLoadingContent : public nsIStreamListener,
*/
bool BlockEmbedOrObjectContentLoading();
/**
* Updates and stores the container's feature policy in its canonical browsing
* context. This gets called whenever the feature policy has changed, which
* can happen when this element is upgraded to a container or when the URI of
* the element has changed.
*/
void RefreshFeaturePolicy();
private:
// Object parameter changes returned by UpdateObjectParameters
enum ParameterUpdateFlags {
@ -393,6 +402,14 @@ class nsObjectLoadingContent : public nsIStreamListener,
*/
void MaybeStoreCrossOriginFeaturePolicy();
/**
* Return the value of either `data` or `src`, depending on element type,
* parsed as a URL. If URL is invalid or the attribute is missing this returns
* the document's origin.
*/
static already_AddRefed<nsIPrincipal> GetFeaturePolicyDefaultOrigin(
nsINode* aNode);
// The final listener for mChannel (uriloader, pluginstreamlistener, etc.)
nsCOMPtr<nsIStreamListener> mFinalListener;
@ -464,6 +481,14 @@ class nsObjectLoadingContent : public nsIStreamListener,
// our own frame.
mozilla::Maybe<mozilla::IntrinsicSize> mSubdocumentIntrinsicSize;
mozilla::Maybe<mozilla::AspectRatio> mSubdocumentIntrinsicRatio;
// This gets created on the first call of `RefreshFeaturePolicy`, and will be
// kept after that. Navigations of this element will use this if they're
// targetting documents, which is how iframe element works. If it's a
// non-document the feature policy isn't used, but it doesn't hurt to keep it
// around, and a subsequent document load will continue using it after
// refreshing it.
RefPtr<mozilla::dom::FeaturePolicy> mFeaturePolicy;
};
#endif

View File

@ -79,6 +79,10 @@ void HTMLEmbedElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
}
if (aName == nsGkAtoms::src) {
RefreshFeaturePolicy();
}
if (aNamespaceID == kNameSpaceID_None &&
aName == nsGkAtoms::allowfullscreen && mFrameLoader) {
if (auto* bc = mFrameLoader->GetExtantBrowsingContext()) {

View File

@ -100,6 +100,11 @@ void HTMLObjectElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
nsIPrincipal* aSubjectPrincipal,
bool aNotify) {
AfterMaybeChangeAttr(aNamespaceID, aName, aNotify);
if (aName == nsGkAtoms::data) {
RefreshFeaturePolicy();
}
return nsGenericHTMLFormControlElement::AfterSetAttr(
aNamespaceID, aName, aValue, aOldValue, aSubjectPrincipal, aNotify);
}
@ -126,6 +131,7 @@ void HTMLObjectElement::AfterMaybeChangeAttr(int32_t aNamespaceID,
BlockEmbedOrObjectContentLoading()) {
return;
}
nsContentUtils::AddScriptRunner(NS_NewRunnableFunction(
"HTMLObjectElement::LoadObject",
[self = RefPtr<HTMLObjectElement>(this), aNotify]() {

View File

@ -2048,6 +2048,15 @@ bool DocumentLoadListener::MaybeTriggerProcessSwitch(
return;
}
// At this point the element has stored the container feature policy in
// the new browsing context, but we need to make sure that we copy it
// over to the load info.
nsCOMPtr<nsILoadInfo> loadInfo = self->mChannel->LoadInfo();
if (aBrowsingContext->GetContainerFeaturePolicy()) {
loadInfo->SetContainerFeaturePolicyInfo(
*aBrowsingContext->GetContainerFeaturePolicy());
}
MOZ_LOG(gProcessIsolationLog, LogLevel::Verbose,
("Process Switch: Upgraded Object to Document Load"));
self->TriggerProcessSwitch(aBrowsingContext, options);