tor-browser

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

HTMLMetaElement.cpp (6389B)


      1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
      2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
      3 /* This Source Code Form is subject to the terms of the Mozilla Public
      4 * License, v. 2.0. If a copy of the MPL was not distributed with this
      5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      6 
      7 #include "mozilla/dom/HTMLMetaElement.h"
      8 
      9 #include "mozilla/AsyncEventDispatcher.h"
     10 #include "mozilla/Logging.h"
     11 #include "mozilla/StaticPrefs_security.h"
     12 #include "mozilla/dom/BindContext.h"
     13 #include "mozilla/dom/HTMLMetaElementBinding.h"
     14 #include "mozilla/dom/ViewportMetaData.h"
     15 #include "mozilla/dom/nsCSPService.h"
     16 #include "mozilla/dom/nsCSPUtils.h"
     17 #include "nsContentUtils.h"
     18 #include "nsIXMLContentSink.h"
     19 #include "nsSandboxFlags.h"
     20 #include "nsStyleConsts.h"
     21 
     22 static mozilla::LazyLogModule gMetaElementLog("nsMetaElement");
     23 #define LOG(msg) MOZ_LOG(gMetaElementLog, mozilla::LogLevel::Debug, msg)
     24 #define LOG_ENABLED() MOZ_LOG_TEST(gMetaElementLog, mozilla::LogLevel::Debug)
     25 
     26 NS_IMPL_NS_NEW_HTML_ELEMENT(Meta)
     27 
     28 namespace mozilla::dom {
     29 
     30 HTMLMetaElement::HTMLMetaElement(
     31    already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo)
     32    : nsGenericHTMLElement(std::move(aNodeInfo)) {}
     33 
     34 HTMLMetaElement::~HTMLMetaElement() = default;
     35 
     36 NS_IMPL_ELEMENT_CLONE(HTMLMetaElement)
     37 
     38 void HTMLMetaElement::AfterSetAttr(int32_t aNameSpaceID, nsAtom* aName,
     39                                   const nsAttrValue* aValue,
     40                                   const nsAttrValue* aOldValue,
     41                                   nsIPrincipal* aSubjectPrincipal,
     42                                   bool aNotify) {
     43  if (aNameSpaceID == kNameSpaceID_None) {
     44    if (Document* document = GetUncomposedDoc()) {
     45      if (aName == nsGkAtoms::content) {
     46        if (const nsAttrValue* name = GetParsedAttr(nsGkAtoms::name)) {
     47          MetaAddedOrChanged(*document, *name, ChangeKind::ContentChange);
     48        }
     49        CreateAndDispatchEvent(*document, u"DOMMetaChanged"_ns);
     50      } else if (aName == nsGkAtoms::name) {
     51        if (aOldValue) {
     52          MetaRemoved(*document, *aOldValue, ChangeKind::NameChange);
     53        }
     54        if (aValue) {
     55          MetaAddedOrChanged(*document, *aValue, ChangeKind::NameChange);
     56        }
     57        CreateAndDispatchEvent(*document, u"DOMMetaChanged"_ns);
     58      }
     59    }
     60  }
     61 
     62  return nsGenericHTMLElement::AfterSetAttr(
     63      aNameSpaceID, aName, aValue, aOldValue, aSubjectPrincipal, aNotify);
     64 }
     65 
     66 nsresult HTMLMetaElement::BindToTree(BindContext& aContext, nsINode& aParent) {
     67  nsresult rv = nsGenericHTMLElement::BindToTree(aContext, aParent);
     68  NS_ENSURE_SUCCESS(rv, rv);
     69  if (!IsInUncomposedDoc()) {
     70    return rv;
     71  }
     72  Document& doc = aContext.OwnerDoc();
     73 
     74  bool shouldProcessMeta = true;
     75  // We don't want to call ProcessMETATag when we are pretty print
     76  // the document
     77  if (doc.IsXMLDocument()) {
     78    if (nsCOMPtr<nsIXMLContentSink> xmlSink =
     79            do_QueryInterface(doc.GetCurrentContentSink())) {
     80      if (xmlSink->IsPrettyPrintXML() &&
     81          xmlSink->IsPrettyPrintHasSpecialRoot()) {
     82        shouldProcessMeta = false;
     83      }
     84    }
     85  }
     86 
     87  if (shouldProcessMeta) {
     88    doc.ProcessMETATag(this);
     89  }
     90 
     91  if (AttrValueIs(kNameSpaceID_None, nsGkAtoms::httpEquiv, nsGkAtoms::headerCSP,
     92                  eIgnoreCase)) {
     93    // only accept <meta http-equiv="Content-Security-Policy" content=""> if it
     94    // appears in the <head> element.
     95    Element* headElt = doc.GetHeadElement();
     96    if (headElt && IsInclusiveDescendantOf(headElt)) {
     97      nsAutoString content;
     98      GetContent(content);
     99 
    100      if (LOG_ENABLED()) {
    101        nsAutoCString documentURIspec;
    102        if (nsIURI* documentURI = doc.GetDocumentURI()) {
    103          documentURI->GetAsciiSpec(documentURIspec);
    104        }
    105 
    106        LOG(
    107            ("HTMLMetaElement %p sets CSP '%s' on document=%p, "
    108             "document-uri=%s",
    109             this, NS_ConvertUTF16toUTF8(content).get(), &doc,
    110             documentURIspec.get()));
    111      }
    112      CSP_ApplyMetaCSPToDoc(doc, content);
    113    }
    114  }
    115 
    116  if (const nsAttrValue* name = GetParsedAttr(nsGkAtoms::name)) {
    117    MetaAddedOrChanged(doc, *name, ChangeKind::TreeChange);
    118  }
    119  CreateAndDispatchEvent(doc, u"DOMMetaAdded"_ns);
    120  return rv;
    121 }
    122 
    123 void HTMLMetaElement::UnbindFromTree(UnbindContext& aContext) {
    124  if (Document* oldDoc = GetUncomposedDoc()) {
    125    if (const nsAttrValue* name = GetParsedAttr(nsGkAtoms::name)) {
    126      MetaRemoved(*oldDoc, *name, ChangeKind::TreeChange);
    127    }
    128    CreateAndDispatchEvent(*oldDoc, u"DOMMetaRemoved"_ns);
    129  }
    130  nsGenericHTMLElement::UnbindFromTree(aContext);
    131 }
    132 
    133 void HTMLMetaElement::CreateAndDispatchEvent(Document&,
    134                                             const nsAString& aEventName) {
    135  AsyncEventDispatcher::RunDOMEventWhenSafe(*this, aEventName, CanBubble::eYes,
    136                                            ChromeOnlyDispatch::eYes);
    137 }
    138 
    139 JSObject* HTMLMetaElement::WrapNode(JSContext* aCx,
    140                                    JS::Handle<JSObject*> aGivenProto) {
    141  return HTMLMetaElement_Binding::Wrap(aCx, this, aGivenProto);
    142 }
    143 
    144 void HTMLMetaElement::MetaAddedOrChanged(Document& aDoc,
    145                                         const nsAttrValue& aName,
    146                                         ChangeKind aChangeKind) {
    147  nsAutoString content;
    148  const bool hasContent = GetAttr(nsGkAtoms::content, content);
    149  if (aName.Equals(nsGkAtoms::viewport, eIgnoreCase)) {
    150    if (hasContent) {
    151      aDoc.SetMetaViewportData(MakeUnique<ViewportMetaData>(content));
    152    }
    153    return;
    154  }
    155 
    156  if (aName.Equals(nsGkAtoms::referrer, eIgnoreCase)) {
    157    content = nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
    158        content);
    159    return aDoc.UpdateReferrerInfoFromMeta(content,
    160                                           /* aPreload = */ false);
    161  }
    162  if (aName.Equals(nsGkAtoms::color_scheme, eIgnoreCase)) {
    163    if (aChangeKind != ChangeKind::ContentChange) {
    164      return aDoc.AddColorSchemeMeta(*this);
    165    }
    166    return aDoc.RecomputeColorScheme();
    167  }
    168 }
    169 
    170 void HTMLMetaElement::MetaRemoved(Document& aDoc, const nsAttrValue& aName,
    171                                  ChangeKind aChangeKind) {
    172  MOZ_ASSERT(aChangeKind != ChangeKind::ContentChange,
    173             "Content change can't trigger removal");
    174  if (aName.Equals(nsGkAtoms::color_scheme, eIgnoreCase)) {
    175    return aDoc.RemoveColorSchemeMeta(*this);
    176  }
    177 }
    178 
    179 }  // namespace mozilla::dom