tor-browser

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

XMLDocument.cpp (12054B)


      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/XMLDocument.h"
      8 
      9 #include "mozilla/BasicEvents.h"
     10 #include "mozilla/Encoding.h"
     11 #include "mozilla/EventDispatcher.h"
     12 #include "mozilla/dom/Attr.h"
     13 #include "mozilla/dom/DocGroup.h"
     14 #include "mozilla/dom/DocumentBinding.h"
     15 #include "mozilla/dom/DocumentType.h"
     16 #include "mozilla/dom/Element.h"
     17 #include "mozilla/dom/XMLDocumentBinding.h"
     18 #include "nsCExternalHandlerService.h"
     19 #include "nsCOMPtr.h"
     20 #include "nsCRT.h"
     21 #include "nsCharsetSource.h"
     22 #include "nsComponentManagerUtils.h"
     23 #include "nsContentCreatorFunctions.h"
     24 #include "nsContentPolicyUtils.h"
     25 #include "nsContentUtils.h"
     26 #include "nsError.h"
     27 #include "nsHTMLDocument.h"
     28 #include "nsHTMLParts.h"
     29 #include "nsIConsoleService.h"
     30 #include "nsIContent.h"
     31 #include "nsIDocShell.h"
     32 #include "nsIPrincipal.h"
     33 #include "nsIScriptError.h"
     34 #include "nsIURI.h"
     35 #include "nsIXMLContentSink.h"
     36 #include "nsJSUtils.h"
     37 #include "nsMimeTypes.h"
     38 #include "nsNetUtil.h"
     39 #include "nsParser.h"
     40 #include "nsPresContext.h"
     41 #include "nsString.h"
     42 #include "nsThreadUtils.h"
     43 
     44 using namespace mozilla;
     45 using namespace mozilla::dom;
     46 
     47 // ==================================================================
     48 // =
     49 // ==================================================================
     50 
     51 nsresult NS_NewDOMDocument(Document** aInstancePtrResult,
     52                           const nsAString& aNamespaceURI,
     53                           const nsAString& aQualifiedName,
     54                           DocumentType* aDoctype, nsIURI* aDocumentURI,
     55                           nsIURI* aBaseURI, nsIPrincipal* aPrincipal,
     56                           mozilla::dom::LoadedAsData aLoadedAsData,
     57                           nsIGlobalObject* aEventObject,
     58                           DocumentFlavor aFlavor) {
     59  // Note: can't require that aDocumentURI/aBaseURI/aPrincipal be non-null,
     60  // since at least one caller (XMLHttpRequest) doesn't have decent args to
     61  // pass in.
     62 
     63  nsresult rv;
     64 
     65  *aInstancePtrResult = nullptr;
     66 
     67  nsCOMPtr<Document> d;
     68  bool isHTML = false;
     69  bool isXHTML = false;
     70  if (aFlavor == DocumentFlavor::SVG) {
     71    rv = NS_NewSVGDocument(getter_AddRefs(d), aPrincipal, aPrincipal,
     72                           aLoadedAsData);
     73  } else if (aFlavor == DocumentFlavor::HTML) {
     74    rv = NS_NewHTMLDocument(getter_AddRefs(d), aPrincipal, aPrincipal,
     75                            aLoadedAsData);
     76    isHTML = true;
     77  } else if (aFlavor == DocumentFlavor::XML) {
     78    rv = NS_NewXMLDocument(getter_AddRefs(d), aPrincipal, aPrincipal,
     79                           aLoadedAsData);
     80  } else if (aFlavor == DocumentFlavor::Plain) {
     81    rv = NS_NewXMLDocument(getter_AddRefs(d), aPrincipal, aPrincipal,
     82                           aLoadedAsData, true);
     83  } else if (aDoctype) {
     84    MOZ_ASSERT(aFlavor == DocumentFlavor::LegacyGuess);
     85    nsAutoString publicId, name;
     86    aDoctype->GetPublicId(publicId);
     87    if (publicId.IsEmpty()) {
     88      aDoctype->GetName(name);
     89    }
     90    if (name.EqualsLiteral("html") ||
     91        publicId.EqualsLiteral("-//W3C//DTD HTML 4.01//EN") ||
     92        publicId.EqualsLiteral("-//W3C//DTD HTML 4.01 Frameset//EN") ||
     93        publicId.EqualsLiteral("-//W3C//DTD HTML 4.01 Transitional//EN") ||
     94        publicId.EqualsLiteral("-//W3C//DTD HTML 4.0//EN") ||
     95        publicId.EqualsLiteral("-//W3C//DTD HTML 4.0 Frameset//EN") ||
     96        publicId.EqualsLiteral("-//W3C//DTD HTML 4.0 Transitional//EN")) {
     97      rv = NS_NewHTMLDocument(getter_AddRefs(d), aPrincipal, aPrincipal,
     98                              aLoadedAsData);
     99      isHTML = true;
    100    } else if (publicId.EqualsLiteral("-//W3C//DTD XHTML 1.0 Strict//EN") ||
    101               publicId.EqualsLiteral(
    102                   "-//W3C//DTD XHTML 1.0 Transitional//EN") ||
    103               publicId.EqualsLiteral("-//W3C//DTD XHTML 1.0 Frameset//EN")) {
    104      rv = NS_NewHTMLDocument(getter_AddRefs(d), aPrincipal, aPrincipal,
    105                              aLoadedAsData);
    106      isHTML = true;
    107      isXHTML = true;
    108    } else if (publicId.EqualsLiteral("-//W3C//DTD SVG 1.1//EN")) {
    109      rv = NS_NewSVGDocument(getter_AddRefs(d), aPrincipal, aPrincipal,
    110                             aLoadedAsData);
    111    } else {
    112      rv = NS_NewXMLDocument(getter_AddRefs(d), aPrincipal, aPrincipal,
    113                             aLoadedAsData);
    114    }
    115  } else {
    116    MOZ_ASSERT(aFlavor == DocumentFlavor::LegacyGuess);
    117    rv = NS_NewXMLDocument(getter_AddRefs(d), aPrincipal, aPrincipal,
    118                           aLoadedAsData);
    119  }
    120 
    121  if (NS_FAILED(rv)) {
    122    return rv;
    123  }
    124 
    125  if (isHTML) {
    126    d->SetCompatibilityMode(eCompatibility_FullStandards);
    127    d->AsHTMLDocument()->SetIsXHTML(isXHTML);
    128  }
    129  d->SetLoadedAsData(aLoadedAsData != mozilla::dom::LoadedAsData::No,
    130                     /* aConsiderForMemoryReporting */ true);
    131  d->SetDocumentURI(aDocumentURI);
    132  d->SetBaseURI(aBaseURI);
    133 
    134  // We need to set the script handling object after we set the principal such
    135  // that the doc group is assigned correctly.
    136  if (nsCOMPtr<nsIScriptGlobalObject> sgo = do_QueryInterface(aEventObject)) {
    137    d->SetScriptHandlingObject(sgo);
    138  } else if (aEventObject) {
    139    d->SetScopeObject(aEventObject);
    140  }
    141 
    142  // XMLDocuments and documents "created in memory" get to be UTF-8 by default,
    143  // unlike the legacy HTML mess
    144  d->SetDocumentCharacterSet(UTF_8_ENCODING);
    145 
    146  if (aDoctype) {
    147    ErrorResult result;
    148    d->AppendChild(*aDoctype, result);
    149    // Need to WouldReportJSException() if our callee can throw a JS
    150    // exception (which it can) and we're neither propagating the
    151    // error out nor unconditionally suppressing it.
    152    result.WouldReportJSException();
    153    if (NS_WARN_IF(result.Failed())) {
    154      return result.StealNSResult();
    155    }
    156  }
    157 
    158  if (!aQualifiedName.IsEmpty()) {
    159    ErrorResult result;
    160    ElementCreationOptionsOrString options;
    161    (void)options.SetAsString();
    162 
    163    nsCOMPtr<Element> root =
    164        d->CreateElementNS(aNamespaceURI, aQualifiedName, options, result);
    165    if (NS_WARN_IF(result.Failed())) {
    166      return result.StealNSResult();
    167    }
    168 
    169    d->AppendChild(*root, result);
    170    // Need to WouldReportJSException() if our callee can throw a JS
    171    // exception (which it can) and we're neither propagating the
    172    // error out nor unconditionally suppressing it.
    173    result.WouldReportJSException();
    174    if (NS_WARN_IF(result.Failed())) {
    175      return result.StealNSResult();
    176    }
    177  }
    178 
    179  d.forget(aInstancePtrResult);
    180 
    181  return NS_OK;
    182 }
    183 
    184 nsresult NS_NewXMLDocument(Document** aInstancePtrResult,
    185                           nsIPrincipal* aPrincipal,
    186                           nsIPrincipal* aPartitionedPrincipal,
    187                           mozilla::dom::LoadedAsData aLoadedAsData,
    188                           bool aIsPlainDocument) {
    189  RefPtr<XMLDocument> doc = new XMLDocument("application/xml", aLoadedAsData);
    190 
    191  nsresult rv = doc->Init(aPrincipal, aPartitionedPrincipal);
    192 
    193  if (NS_FAILED(rv)) {
    194    *aInstancePtrResult = nullptr;
    195    return rv;
    196  }
    197 
    198  doc->SetLoadedAsData(aLoadedAsData != mozilla::dom::LoadedAsData::No,
    199                       /* aConsiderForMemoryReporting */ true);
    200  doc->mIsPlainDocument = aIsPlainDocument;
    201  doc.forget(aInstancePtrResult);
    202 
    203  return NS_OK;
    204 }
    205 
    206 namespace mozilla::dom {
    207 
    208 XMLDocument::XMLDocument(const char* aContentType,
    209                         mozilla::dom::LoadedAsData aLoadedAsData)
    210    : Document(aContentType, aLoadedAsData),
    211      mChannelIsPending(false),
    212      mIsPlainDocument(false),
    213      mSuppressParserErrorElement(false),
    214      mSuppressParserErrorConsoleMessages(false) {
    215  mType = eGenericXML;
    216 }
    217 
    218 nsresult XMLDocument::Init(nsIPrincipal* aPrincipal,
    219                           nsIPrincipal* aPartitionedPrincipal) {
    220  nsresult rv = Document::Init(aPrincipal, aPartitionedPrincipal);
    221  NS_ENSURE_SUCCESS(rv, rv);
    222 
    223  return rv;
    224 }
    225 
    226 void XMLDocument::Reset(nsIChannel* aChannel, nsILoadGroup* aLoadGroup) {
    227  Document::Reset(aChannel, aLoadGroup);
    228 }
    229 
    230 void XMLDocument::ResetToURI(nsIURI* aURI, nsILoadGroup* aLoadGroup,
    231                             nsIPrincipal* aPrincipal,
    232                             nsIPrincipal* aPartitionedPrincipal) {
    233  if (mChannelIsPending) {
    234    StopDocumentLoad();
    235    mChannel->CancelWithReason(NS_BINDING_ABORTED,
    236                               "XMLDocument::ResetToURI"_ns);
    237    mChannelIsPending = false;
    238  }
    239 
    240  Document::ResetToURI(aURI, aLoadGroup, aPrincipal, aPartitionedPrincipal);
    241 }
    242 
    243 void XMLDocument::SetSuppressParserErrorElement(bool aSuppress) {
    244  mSuppressParserErrorElement = aSuppress;
    245 }
    246 
    247 bool XMLDocument::SuppressParserErrorElement() {
    248  return mSuppressParserErrorElement;
    249 }
    250 
    251 void XMLDocument::SetSuppressParserErrorConsoleMessages(bool aSuppress) {
    252  mSuppressParserErrorConsoleMessages = aSuppress;
    253 }
    254 
    255 bool XMLDocument::SuppressParserErrorConsoleMessages() {
    256  return mSuppressParserErrorConsoleMessages;
    257 }
    258 
    259 nsresult XMLDocument::StartDocumentLoad(
    260    const char* aCommand, nsIChannel* aChannel, nsILoadGroup* aLoadGroup,
    261    nsISupports* aContainer, nsIStreamListener** aDocListener, bool aReset) {
    262  nsresult rv = Document::StartDocumentLoad(aCommand, aChannel, aLoadGroup,
    263                                            aContainer, aDocListener, aReset);
    264  if (NS_FAILED(rv)) return rv;
    265 
    266  int32_t charsetSource = kCharsetFromDocTypeDefault;
    267  NotNull<const Encoding*> encoding = UTF_8_ENCODING;
    268  TryChannelCharset(aChannel, charsetSource, encoding, nullptr);
    269 
    270  nsCOMPtr<nsIURI> aUrl;
    271  rv = aChannel->GetURI(getter_AddRefs(aUrl));
    272  if (NS_FAILED(rv)) return rv;
    273 
    274  mParser = new nsParser();
    275 
    276  nsCOMPtr<nsIXMLContentSink> sink;
    277 
    278  nsCOMPtr<nsIDocShell> docShell;
    279  if (aContainer) {
    280    docShell = do_QueryInterface(aContainer);
    281    NS_ENSURE_TRUE(docShell, NS_ERROR_FAILURE);
    282  }
    283  rv = NS_NewXMLContentSink(getter_AddRefs(sink), this, aUrl, docShell,
    284                            aChannel);
    285  NS_ENSURE_SUCCESS(rv, rv);
    286 
    287  // Set the parser as the stream listener for the document loader...
    288  rv = CallQueryInterface(mParser, aDocListener);
    289  NS_ENSURE_SUCCESS(rv, rv);
    290 
    291  NS_ASSERTION(mChannel, "How can we not have a channel here?");
    292  mChannelIsPending = true;
    293 
    294  SetDocumentCharacterSet(encoding);
    295  mParser->SetDocumentCharset(encoding, charsetSource);
    296  mParser->SetCommand(aCommand);
    297  mParser->SetContentSink(sink);
    298  mParser->Parse(aUrl);
    299 
    300  return NS_OK;
    301 }
    302 
    303 void XMLDocument::EndLoad() {
    304  mChannelIsPending = false;
    305 
    306  mSynchronousDOMContentLoaded = mLoadedAsData;
    307  Document::EndLoad();
    308  if (mSynchronousDOMContentLoaded) {
    309    mSynchronousDOMContentLoaded = false;
    310    Document::SetReadyStateInternal(Document::READYSTATE_COMPLETE);
    311    // Generate a document load event for the case when an XML
    312    // document was loaded as pure data without any presentation
    313    // attached to it.
    314    WidgetEvent event(true, eLoad);
    315    EventDispatcher::Dispatch(this, nullptr, &event);
    316  }
    317 }
    318 
    319 /* virtual */
    320 void XMLDocument::DocAddSizeOfExcludingThis(nsWindowSizes& aWindowSizes) const {
    321  Document::DocAddSizeOfExcludingThis(aWindowSizes);
    322 }
    323 
    324 // Document interface
    325 
    326 nsresult XMLDocument::Clone(dom::NodeInfo* aNodeInfo, nsINode** aResult) const {
    327  NS_ASSERTION(aNodeInfo->NodeInfoManager() == mNodeInfoManager,
    328               "Can't import this document into another document!");
    329 
    330  RefPtr<XMLDocument> clone =
    331      new XMLDocument("application/xml", LoadedAsData::AsData);
    332  nsresult rv = CloneDocHelper(clone);
    333  NS_ENSURE_SUCCESS(rv, rv);
    334 
    335  // State from XMLDocument
    336  clone->mIsPlainDocument = mIsPlainDocument;
    337 
    338  clone.forget(aResult);
    339  return NS_OK;
    340 }
    341 
    342 JSObject* XMLDocument::WrapNode(JSContext* aCx,
    343                                JS::Handle<JSObject*> aGivenProto) {
    344  if (mIsPlainDocument) {
    345    return Document_Binding::Wrap(aCx, this, aGivenProto);
    346  }
    347 
    348  return XMLDocument_Binding::Wrap(aCx, this, aGivenProto);
    349 }
    350 
    351 }  // namespace mozilla::dom