tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

commit 6bc0995a91e5a29f4e9d299e738085dcd474fda4
parent 969dea41d211479acd825a9bab1b8d456a7b0731
Author: Tom Schuster <tschuster@mozilla.com>
Date:   Tue, 28 Oct 2025 16:15:49 +0000

Bug 1995715 - Sanitizer: Give elements and attributes their own class. r=smaug

Differential Revision: https://phabricator.services.mozilla.com/D269560

Diffstat:
Mdom/security/sanitizer/Sanitizer.cpp | 130+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Mdom/security/sanitizer/Sanitizer.h | 14+++++++-------
Mdom/security/sanitizer/SanitizerTypes.cpp | 60++++++++++++++++++++++++++++++++++++------------------------
Mdom/security/sanitizer/SanitizerTypes.h | 92++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
4 files changed, 179 insertions(+), 117 deletions(-)

diff --git a/dom/security/sanitizer/Sanitizer.cpp b/dom/security/sanitizer/Sanitizer.cpp @@ -192,7 +192,7 @@ void Sanitizer::SetDefaultConfig() { // https://wicg.github.io/sanitizer-api/#canonicalize-a-sanitizer-element template <typename SanitizerElement> -static CanonicalName CanonicalizeElement(const SanitizerElement& aElement) { +static CanonicalElement CanonicalizeElement(const SanitizerElement& aElement) { // return the result of canonicalize a sanitizer name with element and the // HTML namespace as the default namespace. @@ -203,7 +203,7 @@ static CanonicalName CanonicalizeElement(const SanitizerElement& aElement) { // → defaultNamespace]». if (aElement.IsString()) { RefPtr<nsAtom> nameAtom = NS_AtomizeMainThread(aElement.GetAsString()); - return CanonicalName(nameAtom, nsGkAtoms::nsuri_xhtml); + return CanonicalElement(nameAtom, nsGkAtoms::nsuri_xhtml); } // Step 3. Assert: name is a dictionary and both name["name"] and @@ -223,12 +223,12 @@ static CanonicalName CanonicalizeElement(const SanitizerElement& aElement) { // ) // ]». RefPtr<nsAtom> nameAtom = NS_AtomizeMainThread(elem.mName); - return CanonicalName(nameAtom, namespaceAtom); + return CanonicalElement(nameAtom, namespaceAtom); } // https://wicg.github.io/sanitizer-api/#canonicalize-a-sanitizer-attribute template <typename SanitizerAttribute> -static CanonicalName CanonicalizeAttribute( +static CanonicalAttribute CanonicalizeAttribute( const SanitizerAttribute& aAttribute) { // return the result of canonicalize a sanitizer name with attribute and // null as the default namespace. @@ -240,7 +240,7 @@ static CanonicalName CanonicalizeAttribute( // → defaultNamespace]». if (aAttribute.IsString()) { RefPtr<nsAtom> nameAtom = NS_AtomizeMainThread(aAttribute.GetAsString()); - return CanonicalName(nameAtom, nullptr); + return CanonicalAttribute(nameAtom, nullptr); } // Step 3. Assert: name is a dictionary and both name["name"] and @@ -260,7 +260,7 @@ static CanonicalName CanonicalizeAttribute( // ) // ]». RefPtr<nsAtom> nameAtom = NS_AtomizeMainThread(attr.mName); - return CanonicalName(nameAtom, namespaceAtom); + return CanonicalAttribute(nameAtom, namespaceAtom); } // https://wicg.github.io/sanitizer-api/#canonicalize-a-sanitizer-element-with-attributes @@ -284,13 +284,13 @@ static CanonicalElementAttributes CanonicalizeElementAttributes( // Step 2.1. If element["attributes"] exists: if (elem.mAttributes.WasPassed()) { // Step 2.1.1. Let attributes be « ». - CanonicalNameSet attributes; + CanonicalAttributeSet attributes; // Step 2.1.2. For each attribute of element["attributes"]: for (const auto& attribute : elem.mAttributes.Value()) { // Step 2.1.2.1. Append the result of canonicalize a sanitizer attribute // with attribute to attributes. - CanonicalName canonicalAttr = CanonicalizeAttribute(attribute); + CanonicalAttribute canonicalAttr = CanonicalizeAttribute(attribute); if (!attributes.EnsureInserted(canonicalAttr)) { if (aErrorMsg) { aErrorMsg->Assign(nsFmtCString( @@ -308,13 +308,13 @@ static CanonicalElementAttributes CanonicalizeElementAttributes( // Step 2.2. If element["attributes"] exists: if (elem.mRemoveAttributes.WasPassed()) { // Step 2.2.1. Let attributes be « ». - CanonicalNameSet attributes; + CanonicalAttributeSet attributes; // Step 2.2.2. For each attribute of element["removeAttributes"]: for (const auto& attribute : elem.mRemoveAttributes.Value()) { // Step 2.2.2.1. Append the result of canonicalize a sanitizer attribute // with attribute to attributes. - CanonicalName canonicalAttr = CanonicalizeAttribute(attribute); + CanonicalAttribute canonicalAttr = CanonicalizeAttribute(attribute); if (!attributes.EnsureInserted(canonicalAttr)) { if (aErrorMsg) { aErrorMsg->Assign(nsFmtCString( @@ -335,7 +335,7 @@ static CanonicalElementAttributes CanonicalizeElementAttributes( // result["removeAttributes"] exist: if (!result.mAttributes && !result.mRemoveAttributes) { // Step 3.1. Set result["removeAttributes"] to « ». - CanonicalNameSet set{}; + CanonicalAttributeSet set{}; result.mRemoveAttributes = Some(std::move(set)); } @@ -375,7 +375,7 @@ void Sanitizer::CanonicalizeConfiguration(const SanitizerConfig& aConfig, for (const auto& element : aConfig.mElements.Value()) { // Step 3.3.2.1. Append the result of canonicalize a sanitizer element // with attributes element to elements. - CanonicalName elementName = CanonicalizeElement(element); + CanonicalElement elementName = CanonicalizeElement(element); if (elements.Contains(elementName)) { aRv.ThrowTypeError(nsFmtCString( FMT_STRING("Duplicate element {} in 'elements'."), elementName)); @@ -399,13 +399,13 @@ void Sanitizer::CanonicalizeConfiguration(const SanitizerConfig& aConfig, // Step 4. If configuration["removeElements"] exists: if (aConfig.mRemoveElements.WasPassed()) { // Step 4.1. Let elements be « [] » - CanonicalNameSet elements; + CanonicalElementSet elements; // Step 4.2. For each element of configuration["removeElements"] do: for (const auto& element : aConfig.mRemoveElements.Value()) { // Step 4.2.1. Append the result of canonicalize a sanitizer element // element to elements. - CanonicalName canonical = CanonicalizeElement(element); + CanonicalElement canonical = CanonicalizeElement(element); if (!elements.EnsureInserted(canonical)) { aRv.ThrowTypeError(nsFmtCString( FMT_STRING("Duplicate element {} in 'removeElements'."), @@ -421,14 +421,14 @@ void Sanitizer::CanonicalizeConfiguration(const SanitizerConfig& aConfig, // Step 5. If configuration["replaceWithChildrenElements"] exists: if (aConfig.mReplaceWithChildrenElements.WasPassed()) { // Step 5.1. Let elements be « [] » - CanonicalNameSet elements; + CanonicalElementSet elements; // Step 5.2. For each element of // configuration["replaceWithChildrenElements"] do: for (const auto& element : aConfig.mReplaceWithChildrenElements.Value()) { // Step 5.2.1. Append the result of canonicalize a sanitizer element // element to elements. - CanonicalName canonical = CanonicalizeElement(element); + CanonicalElement canonical = CanonicalizeElement(element); if (!elements.EnsureInserted(canonical)) { aRv.ThrowTypeError(nsFmtCString( FMT_STRING( @@ -445,13 +445,13 @@ void Sanitizer::CanonicalizeConfiguration(const SanitizerConfig& aConfig, // Step 6. If configuration["attributes"] exists: if (aConfig.mAttributes.WasPassed()) { // Step 6.1. Let attributes be « [] » - CanonicalNameSet attributes; + CanonicalAttributeSet attributes; // Step 6.2. For each attribute of configuration["attributes"] do: for (const auto& attribute : aConfig.mAttributes.Value()) { // Step 6.2.1. Append the result of canonicalize a sanitizer attribute // attribute to attributes. - CanonicalName canonical = CanonicalizeAttribute(attribute); + CanonicalAttribute canonical = CanonicalizeAttribute(attribute); if (!attributes.EnsureInserted(canonical)) { aRv.ThrowTypeError(nsFmtCString( FMT_STRING("Duplicate attribute {} in 'attributes'."), canonical)); @@ -466,13 +466,13 @@ void Sanitizer::CanonicalizeConfiguration(const SanitizerConfig& aConfig, // Step 7. If configuration["removeAttributes"] exists: if (aConfig.mRemoveAttributes.WasPassed()) { // Step 7.1. Let attributes be « [] » - CanonicalNameSet attributes; + CanonicalAttributeSet attributes; // Step 7.2. For each attribute of configuration["removeAttributes"] do: for (const auto& attribute : aConfig.mRemoveAttributes.Value()) { // Step 7.2.2. Append the result of canonicalize a sanitizer attribute // attribute to attributes. - CanonicalName canonical = CanonicalizeAttribute(attribute); + CanonicalAttribute canonical = CanonicalizeAttribute(attribute); if (!attributes.EnsureInserted(canonical)) { aRv.ThrowTypeError(nsFmtCString( FMT_STRING("Duplicate attribute {} in 'removeAttributes'."), @@ -545,7 +545,7 @@ void Sanitizer::IsValid(ErrorResult& aRv) { // exist, then the intersection of config[elements] and // config[replaceWithChildrenElements] is empty. if (mElements && mReplaceWithChildrenElements) { - for (const CanonicalName& name : mElements->Keys()) { + for (const CanonicalElement& name : mElements->Keys()) { if (mReplaceWithChildrenElements->Contains(name)) { aRv.ThrowTypeError( nsFmtCString(FMT_STRING("Element {} can't be in both 'elements' " @@ -560,7 +560,7 @@ void Sanitizer::IsValid(ErrorResult& aRv) { // config[replaceWithChildrenElements] exist, then the intersection of // config[removeElements] and config[replaceWithChildrenElements] is empty. if (mRemoveElements && mReplaceWithChildrenElements) { - for (const CanonicalName& name : *mRemoveElements) { + for (const CanonicalElement& name : *mRemoveElements) { if (mReplaceWithChildrenElements->Contains(name)) { aRv.ThrowTypeError(nsFmtCString( FMT_STRING("Element {} can't be in both 'removeElements' and " @@ -590,7 +590,7 @@ void Sanitizer::IsValid(ErrorResult& aRv) { // Step 7.1.1.2. The intersection of config[attributes] and // element[attributes] with default « [] » is empty. if (elemAttributes.mAttributes) { - for (const CanonicalName& name : *elemAttributes.mAttributes) { + for (const CanonicalAttribute& name : *elemAttributes.mAttributes) { if (mAttributes->Contains(name)) { aRv.ThrowTypeError(nsFmtCString( FMT_STRING( @@ -605,7 +605,8 @@ void Sanitizer::IsValid(ErrorResult& aRv) { // Step 7.1.1.3. element[removeAttributes] is a subset of // config[attributes]. if (elemAttributes.mRemoveAttributes) { - for (const CanonicalName& name : *elemAttributes.mRemoveAttributes) { + for (const CanonicalAttribute& name : + *elemAttributes.mRemoveAttributes) { if (!mAttributes->Contains(name)) { aRv.ThrowTypeError(nsFmtCString( FMT_STRING( @@ -625,7 +626,7 @@ void Sanitizer::IsValid(ErrorResult& aRv) { // TODO: Merge with loop above? // Step 7.1.1.4.1. element[attributes] does not contain a custom // data attribute. - for (const CanonicalName& name : *elemAttributes.mAttributes) { + for (const CanonicalAttribute& name : *elemAttributes.mAttributes) { if (name.IsDataAttribute()) { aRv.ThrowTypeError(nsFmtCString( FMT_STRING( @@ -646,7 +647,7 @@ void Sanitizer::IsValid(ErrorResult& aRv) { if (*mDataAttributes) { // Step 7.2.1. config[attributes] does not contain a custom data // attribute. - for (const CanonicalName& name : *mAttributes) { + for (const CanonicalAttribute& name : *mAttributes) { if (name.IsDataAttribute()) { aRv.ThrowTypeError(nsFmtCString( FMT_STRING("Data attribute {} in the global 'attributes' is " @@ -686,7 +687,7 @@ void Sanitizer::IsValid(ErrorResult& aRv) { // Step 8.1.3. The intersection of config[removeAttributes] and // element[attributes] with default « [] » is empty. if (elemAttributes.mAttributes) { - for (const CanonicalName& name : *elemAttributes.mAttributes) { + for (const CanonicalAttribute& name : *elemAttributes.mAttributes) { if (mRemoveAttributes->Contains(name)) { aRv.ThrowTypeError(nsFmtCString( FMT_STRING( @@ -701,7 +702,8 @@ void Sanitizer::IsValid(ErrorResult& aRv) { // Step 8.1.4. The intersection of config[removeAttributes] and // element[removeAttributes] with default « [] » is empty. if (elemAttributes.mRemoveAttributes) { - for (const CanonicalName& name : *elemAttributes.mRemoveAttributes) { + for (const CanonicalAttribute& name : + *elemAttributes.mRemoveAttributes) { if (mRemoveAttributes->Contains(name)) { aRv.ThrowTypeError(nsFmtCString( FMT_STRING("Attribute {} can't be part of both the " @@ -773,15 +775,16 @@ void Sanitizer::MaybeMaterializeDefaultConfig() { CanonicalElementAttributes elementAttributes{}; if (name == aElementWithAttributes[i]) { - CanonicalNameSet attributes; + CanonicalAttributeSet attributes; while (aElementWithAttributes[++i]) { - attributes.Insert(CanonicalName(aElementWithAttributes[i], nullptr)); + attributes.Insert( + CanonicalAttribute(aElementWithAttributes[i], nullptr)); } i++; elementAttributes.mAttributes = Some(std::move(attributes)); } - CanonicalName elementName = CanonicalName(name, aNamespace); + CanonicalElement elementName(name, aNamespace); elements.InsertOrUpdate(elementName, std::move(elementAttributes)); } }; @@ -793,9 +796,9 @@ void Sanitizer::MaybeMaterializeDefaultConfig() { kSVGElementWithAttributes); mElements = Some(std::move(elements)); - CanonicalNameSet attributes; + CanonicalAttributeSet attributes; for (nsStaticAtom* name : kDefaultAttributes) { - attributes.Insert(CanonicalName(name, nullptr)); + attributes.Insert(CanonicalAttribute(name, nullptr)); } mAttributes = Some(std::move(attributes)); @@ -835,7 +838,7 @@ void Sanitizer::Get(SanitizerConfig& aConfig) { // order config["removeElements"], with elementA being less than item // elementB. nsTArray<OwningStringOrSanitizerElementNamespace> removeElements; - for (const CanonicalName& canonical : *mRemoveElements) { + for (const CanonicalElement& canonical : *mRemoveElements) { OwningStringOrSanitizerElementNamespace owning; owning.SetAsSanitizerElementNamespace() = canonical.ToSanitizerElementNamespace(); @@ -852,7 +855,7 @@ void Sanitizer::Get(SanitizerConfig& aConfig) { // being less than item elementB. nsTArray<OwningStringOrSanitizerElementNamespace> replaceWithChildrenElements; - for (const CanonicalName& canonical : *mReplaceWithChildrenElements) { + for (const CanonicalElement& canonical : *mReplaceWithChildrenElements) { OwningStringOrSanitizerElementNamespace owning; owning.SetAsSanitizerElementNamespace() = canonical.ToSanitizerElementNamespace(); @@ -894,7 +897,7 @@ bool Sanitizer::AllowElement( // Step 1. Set element to the result of canonicalize a sanitizer element // with attributes with element. - CanonicalName elementName = CanonicalizeElement(aElement); + CanonicalElement elementName = CanonicalizeElement(aElement); // NOTE: Duplicate attributes are removed/ignored. CanonicalElementAttributes elementAttributes = CanonicalizeElementAttributes(aElement); @@ -915,8 +918,8 @@ bool Sanitizer::AllowElement( if (mAttributes) { // Step 2.3.1. If element["attributes"] exists: if (elementAttributes.mAttributes) { - CanonicalNameSet attributes; - for (const CanonicalName& attr : *elementAttributes.mAttributes) { + CanonicalAttributeSet attributes; + for (const CanonicalAttribute& attr : *elementAttributes.mAttributes) { // Step 2.3.1.1. Set element["attributes"] to remove duplicates from // element["attributes"]. MOZ_ASSERT(!attributes.Contains(attr)); @@ -945,8 +948,9 @@ bool Sanitizer::AllowElement( // Step 2.3.2. If element["removeAttributes"] exists: if (elementAttributes.mRemoveAttributes) { - CanonicalNameSet removeAttributes; - for (const CanonicalName& attr : *elementAttributes.mRemoveAttributes) { + CanonicalAttributeSet removeAttributes; + for (const CanonicalAttribute& attr : + *elementAttributes.mRemoveAttributes) { // Step 2.3.2.1. Set element["removeAttributes"] to remove duplicates // from element["removeAttributes"]. // @@ -968,8 +972,8 @@ bool Sanitizer::AllowElement( // Step 2.4.1. If element["attributes"] exists: if (elementAttributes.mAttributes) { - CanonicalNameSet attributes; - for (const CanonicalName& attr : *elementAttributes.mAttributes) { + CanonicalAttributeSet attributes; + for (const CanonicalAttribute& attr : *elementAttributes.mAttributes) { // Step 2.4.1.1. Set element["attributes"] to remove duplicates from // element["attributes"]. // @@ -1000,8 +1004,9 @@ bool Sanitizer::AllowElement( // Step 2.4.2. If element["removeAttributes"] exists: if (elementAttributes.mRemoveAttributes) { - CanonicalNameSet removeAttributes; - for (const CanonicalName& attr : *elementAttributes.mRemoveAttributes) { + CanonicalAttributeSet removeAttributes; + for (const CanonicalAttribute& attr : + *elementAttributes.mRemoveAttributes) { // Step 2.4.2.1. Set element["removeAttributes"] to remove duplicates // from element["removeAttributes"]. MOZ_ASSERT(!removeAttributes.Contains(attr)); @@ -1099,12 +1104,12 @@ bool Sanitizer::RemoveElement( // Step 1. Set element to the result of canonicalize a sanitizer element // with element. - CanonicalName element = CanonicalizeElement(aElement); + CanonicalElement element = CanonicalizeElement(aElement); return RemoveElementCanonical(std::move(element)); } -bool Sanitizer::RemoveElementCanonical(CanonicalName&& aElement) { +bool Sanitizer::RemoveElementCanonical(CanonicalElement&& aElement) { // Step 2. Set modified to the result of remove element from // configuration["replaceWithChildrenElements"]. bool modified = mReplaceWithChildrenElements @@ -1159,7 +1164,7 @@ bool Sanitizer::ReplaceElementWithChildren( // Step 1. Set element to the result of canonicalize a sanitizer element // with element. - CanonicalName element = CanonicalizeElement(aElement); + CanonicalElement element = CanonicalizeElement(aElement); // Step 2. If configuration["replaceWithChildrenElements"] contains element: if (mReplaceWithChildrenElements && @@ -1193,7 +1198,7 @@ bool Sanitizer::AllowAttribute( // Step 1. Set attribute to the result of canonicalize a sanitizer attribute // with attribute. - CanonicalName attribute = CanonicalizeAttribute(aAttribute); + CanonicalAttribute attribute = CanonicalizeAttribute(aAttribute); // Step 2. If configuration["attributes"] exists: if (mAttributes) { @@ -1271,12 +1276,12 @@ bool Sanitizer::RemoveAttribute( // Step 1. Set attribute to the result of canonicalize a sanitizer attribute // with attribute. - CanonicalName attribute = CanonicalizeAttribute(aAttribute); + CanonicalAttribute attribute = CanonicalizeAttribute(aAttribute); return RemoveAttributeCanonical(std::move(attribute)); } -bool Sanitizer::RemoveAttributeCanonical(CanonicalName&& aAttribute) { +bool Sanitizer::RemoveAttributeCanonical(CanonicalAttribute&& aAttribute) { // Step 2. If configuration["attributes"] exists: if (mAttributes) { // Step 2.1. Comment: If we have a global allow-list, we need to add @@ -1397,7 +1402,7 @@ bool Sanitizer::SetDataAttributes(bool aAllow) { // Step 3.1. Remove any items attr from configuration["attributes"] where // attr is a custom data attribute. - mAttributes->RemoveIf([](const CanonicalName& aAttribute) { + mAttributes->RemoveIf([](const CanonicalAttribute& aAttribute) { return aAttribute.IsDataAttribute(); }); @@ -1411,7 +1416,7 @@ bool Sanitizer::SetDataAttributes(bool aAllow) { // Step 3.2.1.1.1. Remove any items attr from element[attributes] // where attr is a custom data attribute. elemAttributes.mAttributes->RemoveIf( - [](const CanonicalName& aAttribute) { + [](const CanonicalAttribute& aAttribute) { return aAttribute.IsDataAttribute(); }); } @@ -1450,12 +1455,12 @@ bool Sanitizer::RemoveUnsafe() { // Step 3. For each element in built-in safe baseline // configuration[removeElements]: -#define ELEMENT(_, NSURI, LOCAL_NAME) \ - /* Step 3.1. Call remove an element element from configuration. */ \ - if (RemoveElementCanonical( \ - CanonicalName(nsGkAtoms::LOCAL_NAME, nsGkAtoms::nsuri_##NSURI))) { \ - /* Step 3.2. If the call returned true, set result to true. */ \ - result = true; \ +#define ELEMENT(_, NSURI, LOCAL_NAME) \ + /* Step 3.1. Call remove an element element from configuration. */ \ + if (RemoveElementCanonical(CanonicalElement(nsGkAtoms::LOCAL_NAME, \ + nsGkAtoms::nsuri_##NSURI))) { \ + /* Step 3.2. If the call returned true, set result to true. */ \ + result = true; \ } FOR_EACH_BASELINE_REMOVE_ELEMENT(ELEMENT) @@ -1472,7 +1477,8 @@ bool Sanitizer::RemoveUnsafe() { EventNameType_All & ~EventNameType_XUL, [self = MOZ_KnownLive(this), &result](nsAtom* aName) { // Step 5.1. Call remove an attribute attribute from configuration. - if (self->RemoveAttributeCanonical(CanonicalName(aName, nullptr))) { + if (self->RemoveAttributeCanonical( + CanonicalAttribute(aName, nullptr))) { // Step 5.2. If the call returned true, set result to true. result = true; } @@ -1575,7 +1581,7 @@ void Sanitizer::SanitizeChildren(nsINode* aNode, bool aSafe) { nsAtom* nameAtom = child->NodeInfo()->NameAtom(); int32_t namespaceID = child->NodeInfo()->NamespaceID(); // Make sure this is optimized away when using the default config. - Maybe<CanonicalName> elementName; + Maybe<CanonicalElement> elementName; // This is only used for the default config case. [[maybe_unused]] StaticAtomSet* elementAttributes = nullptr; if constexpr (!IsDefaultConfig) { @@ -1790,7 +1796,7 @@ static bool RemoveJavascriptNavigationURLAttribute(Element* aElement, } void Sanitizer::SanitizeAttributes(Element* aChild, - const CanonicalName& aElementName, + const CanonicalElement& aElementName, bool aSafe) { MOZ_ASSERT(!mIsDefaultConfig); @@ -1813,7 +1819,7 @@ void Sanitizer::SanitizeAttributes(Element* aChild, const nsAttrName* attr = aChild->GetAttrNameAt(i); RefPtr<nsAtom> attrLocalName = attr->LocalName(); int32_t attrNs = attr->NamespaceID(); - CanonicalName attrName(attrLocalName, ToNamespace(attrNs)); + CanonicalAttribute attrName(attrLocalName, ToNamespace(attrNs)); bool remove = false; // Optimization: Remove unsafe event handler content attributes. diff --git a/dom/security/sanitizer/Sanitizer.h b/dom/security/sanitizer/Sanitizer.h @@ -87,13 +87,13 @@ class Sanitizer final : public nsISupports, public nsWrapperCache { void MaybeMaterializeDefaultConfig(); - bool RemoveElementCanonical(sanitizer::CanonicalName&& aElement); - bool RemoveAttributeCanonical(sanitizer::CanonicalName&& aAttribute); + bool RemoveElementCanonical(sanitizer::CanonicalElement&& aElement); + bool RemoveAttributeCanonical(sanitizer::CanonicalAttribute&& aAttribute); template <bool IsDefaultConfig> void SanitizeChildren(nsINode* aNode, bool aSafe); void SanitizeAttributes(Element* aChild, - const sanitizer::CanonicalName& aElementName, + const sanitizer::CanonicalElement& aElementName, bool aSafe); void SanitizeDefaultConfigAttributes(Element* aChild, StaticAtomSet* aElementAttributes, @@ -131,11 +131,11 @@ class Sanitizer final : public nsISupports, public nsWrapperCache { RefPtr<nsIGlobalObject> mGlobal; Maybe<sanitizer::CanonicalElementMap> mElements; - Maybe<sanitizer::CanonicalNameSet> mRemoveElements; - Maybe<sanitizer::CanonicalNameSet> mReplaceWithChildrenElements; + Maybe<sanitizer::CanonicalElementSet> mRemoveElements; + Maybe<sanitizer::CanonicalElementSet> mReplaceWithChildrenElements; - Maybe<sanitizer::CanonicalNameSet> mAttributes; - Maybe<sanitizer::CanonicalNameSet> mRemoveAttributes; + Maybe<sanitizer::CanonicalAttributeSet> mAttributes; + Maybe<sanitizer::CanonicalAttributeSet> mRemoveAttributes; bool mComments = false; // mDataAttributes always exists when mAttributes exists after diff --git a/dom/security/sanitizer/SanitizerTypes.cpp b/dom/security/sanitizer/SanitizerTypes.cpp @@ -6,39 +6,41 @@ namespace mozilla::dom::sanitizer { -bool CanonicalName::IsDataAttribute() const { - return StringBeginsWith(nsDependentAtomString(mLocalName), u"data-"_ns) && - !mNamespace; -} - -template <typename SanitizerName> -void CanonicalName::SetSanitizerName(SanitizerName& aSanitizerName) const { - mLocalName->ToString(aSanitizerName.mName); - if (mNamespace) { - mNamespace->ToString(aSanitizerName.mNamespace); +template <typename CanonicalName, typename SanitizerName> +static void SetSanitizerName(const CanonicalName& aName, + SanitizerName& aSanitizerName) { + aName->LocalName()->ToString(aSanitizerName.mName); + if (nsAtom* ns = aName->GetNamespace()) { + ns->ToString(aSanitizerName.mNamespace); } else { aSanitizerName.mNamespace.SetIsVoid(true); } } -SanitizerAttributeNamespace CanonicalName::ToSanitizerAttributeNamespace() +bool CanonicalAttribute::IsDataAttribute() const { + return StringBeginsWith(nsDependentAtomString(mLocalName), u"data-"_ns) && + !mNamespace; +} + +SanitizerAttributeNamespace CanonicalAttribute::ToSanitizerAttributeNamespace() const { SanitizerAttributeNamespace result; - SetSanitizerName(result); + SetSanitizerName(this, result); return result; } -SanitizerElementNamespace CanonicalName::ToSanitizerElementNamespace() const { +SanitizerElementNamespace CanonicalElement::ToSanitizerElementNamespace() + const { SanitizerElementNamespace result; - SetSanitizerName(result); + SetSanitizerName(this, result); return result; } SanitizerElementNamespaceWithAttributes -CanonicalName::ToSanitizerElementNamespaceWithAttributes( +CanonicalElement::ToSanitizerElementNamespaceWithAttributes( const CanonicalElementAttributes& aElementAttributes) const { SanitizerElementNamespaceWithAttributes result; - SetSanitizerName(result); + SetSanitizerName(this, result); if (aElementAttributes.mAttributes) { result.mAttributes.Construct( ToSanitizerAttributes(*aElementAttributes.mAttributes)); @@ -50,18 +52,28 @@ CanonicalName::ToSanitizerElementNamespaceWithAttributes( return result; } -std::ostream& operator<<(std::ostream& aStream, const CanonicalName& aName) { +template <typename CanonicalName> +static std::ostream& Write(std::ostream& aStream, const CanonicalName& aName) { nsAutoCString localName; - aName.mLocalName->ToUTF8String(localName); + aName.LocalName()->ToUTF8String(localName); aStream << '"' << localName << '"'; - if (aName.mNamespace) { + if (nsAtom* ns = aName.GetNamespace()) { nsAutoCString nameSpace; - aName.mNamespace->ToUTF8String(nameSpace); + ns->ToUTF8String(nameSpace); return aStream << " (namespace: \"" << nameSpace << "\")"; } return aStream << " (namespace: null)"; } +std::ostream& operator<<(std::ostream& aStream, + const CanonicalAttribute& aName) { + return Write(aStream, aName); +} + +std::ostream& operator<<(std::ostream& aStream, const CanonicalElement& aName) { + return Write(aStream, aName); +} + bool CanonicalElementAttributes::Equals( const CanonicalElementAttributes& aOther) const { if (mAttributes.isSome() != aOther.mAttributes.isSome() || @@ -74,7 +86,7 @@ bool CanonicalElementAttributes::Equals( return false; } - for (const CanonicalName& attr : *mAttributes) { + for (const CanonicalAttribute& attr : *mAttributes) { if (!aOther.mAttributes->Contains(attr)) { return false; } @@ -86,7 +98,7 @@ bool CanonicalElementAttributes::Equals( return false; } - for (const CanonicalName& attr : *mRemoveAttributes) { + for (const CanonicalAttribute& attr : *mRemoveAttributes) { if (!aOther.mRemoveAttributes->Contains(attr)) { return false; } @@ -97,9 +109,9 @@ bool CanonicalElementAttributes::Equals( } nsTArray<OwningStringOrSanitizerAttributeNamespace> ToSanitizerAttributes( - const CanonicalNameSet& aSet) { + const CanonicalAttributeSet& aSet) { nsTArray<OwningStringOrSanitizerAttributeNamespace> attributes; - for (const CanonicalName& canonical : aSet) { + for (const CanonicalAttribute& canonical : aSet) { OwningStringOrSanitizerAttributeNamespace owning; owning.SetAsSanitizerAttributeNamespace() = canonical.ToSanitizerAttributeNamespace(); diff --git a/dom/security/sanitizer/SanitizerTypes.h b/dom/security/sanitizer/SanitizerTypes.h @@ -15,23 +15,22 @@ namespace mozilla::dom::sanitizer { struct CanonicalElementAttributes; -// The name of an element/attribute combined with its namespace. -class CanonicalName : public PLDHashEntryHdr { +class CanonicalAttribute : public PLDHashEntryHdr { public: - using KeyType = const CanonicalName&; - using KeyTypePointer = const CanonicalName*; + using KeyType = const CanonicalAttribute&; + using KeyTypePointer = const CanonicalAttribute*; - explicit CanonicalName(KeyTypePointer aKey) + explicit CanonicalAttribute(const CanonicalAttribute* aKey) : mLocalName(aKey->mLocalName), mNamespace(aKey->mNamespace) {} - CanonicalName(CanonicalName&&) = default; - CanonicalName(RefPtr<nsAtom> aLocalName, RefPtr<nsAtom> aNamespace) + CanonicalAttribute(RefPtr<nsAtom> aLocalName, RefPtr<nsAtom> aNamespace) : mLocalName(std::move(aLocalName)), mNamespace(std::move(aNamespace)) {} - CanonicalName(nsStaticAtom* aLocalName, nsStaticAtom* aNamespace) + CanonicalAttribute(nsStaticAtom* aLocalName, nsStaticAtom* aNamespace) : mLocalName(aLocalName), mNamespace(aNamespace) {} - ~CanonicalName() = default; + CanonicalAttribute(CanonicalAttribute&&) = default; + ~CanonicalAttribute() = default; KeyType GetKey() const { return *this; } - bool KeyEquals(KeyTypePointer aKey) const { + bool KeyEquals(const CanonicalAttribute* aKey) const { return mLocalName == aKey->mLocalName && mNamespace == aKey->mNamespace; } @@ -42,46 +41,87 @@ class CanonicalName : public PLDHashEntryHdr { enum { ALLOW_MEMMOVE = true }; - // Caution: Only use this for attribute names, not elements! // Returns true for names that start with data-* and have a null namespace. bool IsDataAttribute() const; - SanitizerAttributeNamespace ToSanitizerAttributeNamespace() const; + + CanonicalAttribute Clone() const { + return CanonicalAttribute(mLocalName, mNamespace); + } + + nsAtom* LocalName() const { return mLocalName; } + nsAtom* GetNamespace() const { return mNamespace; } + + protected: + friend std::ostream& operator<<(std::ostream& aStream, + const CanonicalAttribute& aName); + RefPtr<nsAtom> mLocalName; + // A "null" namespace is represented by the nullptr. + RefPtr<nsAtom> mNamespace; +}; + +class CanonicalElement : public PLDHashEntryHdr { + public: + using KeyType = const CanonicalElement&; + using KeyTypePointer = const CanonicalElement*; + + explicit CanonicalElement(const CanonicalElement* aKey) + : mLocalName(aKey->mLocalName), mNamespace(aKey->mNamespace) {} + CanonicalElement(RefPtr<nsAtom> aLocalName, RefPtr<nsAtom> aNamespace) + : mLocalName(std::move(aLocalName)), mNamespace(std::move(aNamespace)) {} + CanonicalElement(nsStaticAtom* aLocalName, nsStaticAtom* aNamespace) + : mLocalName(aLocalName), mNamespace(aNamespace) {} + CanonicalElement(CanonicalElement&&) = default; + ~CanonicalElement() = default; + + KeyType GetKey() const { return *this; } + bool KeyEquals(const CanonicalElement* aKey) const { + return mLocalName == aKey->mLocalName && mNamespace == aKey->mNamespace; + } + + static KeyTypePointer KeyToPointer(KeyType aKey) { return &aKey; } + static PLDHashNumber HashKey(KeyTypePointer aKey) { + return mozilla::HashGeneric(aKey->mLocalName.get(), aKey->mNamespace.get()); + } + + enum { ALLOW_MEMMOVE = true }; + SanitizerElementNamespace ToSanitizerElementNamespace() const; SanitizerElementNamespaceWithAttributes ToSanitizerElementNamespaceWithAttributes( const CanonicalElementAttributes& aElementAttributes) const; - CanonicalName Clone() const { return CanonicalName(mLocalName, mNamespace); } + nsAtom* LocalName() const { return mLocalName; } + nsAtom* GetNamespace() const { return mNamespace; } protected: friend std::ostream& operator<<(std::ostream& aStream, - const CanonicalName& aName); - - template <typename SanitizerName> - void SetSanitizerName(SanitizerName& aName) const; + const CanonicalElement& aName); RefPtr<nsAtom> mLocalName; // A "null" namespace is represented by the nullptr. RefPtr<nsAtom> mNamespace; }; -std::ostream& operator<<(std::ostream& aStream, const CanonicalName& aName); +std::ostream& operator<<(std::ostream& aStream, + const CanonicalAttribute& aName); +std::ostream& operator<<(std::ostream& aStream, const CanonicalElement& aName); -using CanonicalNameSet = nsTHashSet<CanonicalName>; +using CanonicalAttributeSet = nsTHashSet<CanonicalAttribute>; +using CanonicalElementSet = nsTHashSet<CanonicalElement>; struct CanonicalElementAttributes { - Maybe<CanonicalNameSet> mAttributes; - Maybe<CanonicalNameSet> mRemoveAttributes; + Maybe<CanonicalAttributeSet> mAttributes; + Maybe<CanonicalAttributeSet> mRemoveAttributes; bool Equals(const CanonicalElementAttributes& aOther) const; }; using CanonicalElementMap = - nsTHashMap<CanonicalName, CanonicalElementAttributes>; + nsTHashMap<CanonicalElement, CanonicalElementAttributes>; nsTArray<OwningStringOrSanitizerAttributeNamespace> ToSanitizerAttributes( - const CanonicalNameSet& aSet); + const CanonicalAttributeSet& aSet); inline const auto& GetAsDictionary( const OwningStringOrSanitizerAttributeNamespace& aOwning) { @@ -161,7 +201,11 @@ class MOZ_STACK_CLASS SanitizerComparator final { } // namespace mozilla::dom::sanitizer template <> -struct fmt::formatter<mozilla::dom::sanitizer::CanonicalName> +struct fmt::formatter<mozilla::dom::sanitizer::CanonicalAttribute> + : ostream_formatter {}; + +template <> +struct fmt::formatter<mozilla::dom::sanitizer::CanonicalElement> : ostream_formatter {}; #endif