tor-browser

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

nsHtml5StringParser.cpp (4894B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 #include "nsHtml5StringParser.h"
      6 #include "nsHtml5DependentUTF16Buffer.h"
      7 #include "nsHtml5Tokenizer.h"
      8 #include "nsHtml5TreeBuilder.h"
      9 #include "nsHtml5TreeOpExecutor.h"
     10 #include "nsIContent.h"
     11 #include "mozilla/dom/Document.h"
     12 #include "mozilla/dom/DocumentFragment.h"
     13 
     14 using mozilla::dom::Document;
     15 
     16 NS_IMPL_ISUPPORTS0(nsHtml5StringParser)
     17 
     18 nsHtml5StringParser::nsHtml5StringParser()
     19    : mBuilder(new nsHtml5OplessBuilder()),
     20      mTreeBuilder(new nsHtml5TreeBuilder(mBuilder)),
     21      mTokenizer(new nsHtml5Tokenizer(mTreeBuilder.get(), false)) {
     22  mTokenizer->setInterner(&mAtomTable);
     23  mTokenizer->setKeepBuffer(true);
     24  mTreeBuilder->setKeepBuffer(true);
     25 }
     26 
     27 nsHtml5StringParser::~nsHtml5StringParser() { ClearCaches(); }
     28 
     29 nsresult nsHtml5StringParser::ParseFragment(
     30    const nsAString& aSourceBuffer, nsIContent* aTargetNode,
     31    nsAtom* aContextLocalName, int32_t aContextNamespace, bool aQuirks,
     32    bool aPreventScriptExecution, bool aAllowDeclarativeShadowRoots) {
     33  NS_ENSURE_TRUE(aSourceBuffer.Length() <= INT32_MAX, NS_ERROR_OUT_OF_MEMORY);
     34 
     35  Document* doc = aTargetNode->OwnerDoc();
     36  nsIURI* uri = doc->GetDocumentURI();
     37  NS_ENSURE_TRUE(uri, NS_ERROR_NOT_AVAILABLE);
     38 
     39  mTreeBuilder->setFragmentContext(aContextLocalName, aContextNamespace,
     40                                   aTargetNode, aQuirks);
     41 
     42 #ifdef DEBUG
     43  if (!aPreventScriptExecution) {
     44    NS_ASSERTION(!aTargetNode->IsInUncomposedDoc(),
     45                 "If script execution isn't prevented, "
     46                 "the target node must not be in doc.");
     47    NS_ASSERTION(
     48        aTargetNode->NodeType() == nsINode::DOCUMENT_FRAGMENT_NODE,
     49        "If script execution isn't prevented, must parse to DOM fragment.");
     50  }
     51 #endif
     52 
     53  mTreeBuilder->SetPreventScriptExecution(aPreventScriptExecution);
     54 
     55  return Tokenize(aSourceBuffer, doc, true, aAllowDeclarativeShadowRoots);
     56 }
     57 
     58 nsresult nsHtml5StringParser::ParseDocument(
     59    const nsAString& aSourceBuffer, Document* aTargetDoc,
     60    bool aScriptingEnabledForNoscriptParsing) {
     61  MOZ_ASSERT(!aTargetDoc->GetFirstChild());
     62 
     63  NS_ENSURE_TRUE(aSourceBuffer.Length() <= INT32_MAX, NS_ERROR_OUT_OF_MEMORY);
     64 
     65  mTreeBuilder->setFragmentContext(nullptr, kNameSpaceID_None, nullptr, false);
     66 
     67  mTreeBuilder->SetPreventScriptExecution(true);
     68 
     69  return Tokenize(aSourceBuffer, aTargetDoc,
     70                  aScriptingEnabledForNoscriptParsing,
     71                  aTargetDoc->AllowsDeclarativeShadowRoots());
     72 }
     73 
     74 void nsHtml5StringParser::ClearCaches() {
     75  mTokenizer->dropBufferIfLongerThan(0);
     76  mTreeBuilder->dropBufferIfLongerThan(0);
     77  if (mCacheClearer) {
     78    mCacheClearer->Disconnect();
     79    mCacheClearer = nullptr;
     80  }
     81 }
     82 
     83 void nsHtml5StringParser::TryCache() {
     84  const int32_t kMaxBuffer = 1024 * 1024;
     85  bool didDrop = mTokenizer->dropBufferIfLongerThan(kMaxBuffer);
     86  didDrop |= mTreeBuilder->dropBufferIfLongerThan(kMaxBuffer);
     87  if (didDrop) {
     88    return;
     89  }
     90 
     91  if (!mCacheClearer) {
     92    mCacheClearer = new CacheClearer(this);
     93    nsCOMPtr<nsIRunnable> runnable = mCacheClearer.get();
     94    NS_DispatchToMainThreadQueue(runnable.forget(),
     95                                 mozilla::EventQueuePriority::Idle);
     96  }
     97 }
     98 
     99 nsresult nsHtml5StringParser::Tokenize(const nsAString& aSourceBuffer,
    100                                       Document* aDocument,
    101                                       bool aScriptingEnabledForNoscriptParsing,
    102                                       bool aDeclarativeShadowRootsAllowed) {
    103  nsIURI* uri = aDocument->GetDocumentURI();
    104 
    105  mBuilder->Init(aDocument, uri, nullptr, nullptr);
    106 
    107  mBuilder->SetParser(this);
    108  mBuilder->SetNodeInfoManager(aDocument->NodeInfoManager());
    109 
    110  // Mark the parser as *not* broken by passing NS_OK
    111  nsresult rv = mBuilder->MarkAsBroken(NS_OK);
    112 
    113  mTreeBuilder->setScriptingEnabled(aScriptingEnabledForNoscriptParsing);
    114  mTreeBuilder->setIsSrcdocDocument(aDocument->IsSrcdocDocument());
    115  mTreeBuilder->setAllowDeclarativeShadowRoots(aDeclarativeShadowRootsAllowed);
    116  mBuilder->Start();
    117  mTokenizer->start();
    118  if (!aSourceBuffer.IsEmpty()) {
    119    bool lastWasCR = false;
    120    nsHtml5DependentUTF16Buffer buffer(aSourceBuffer);
    121    while (buffer.hasMore()) {
    122      buffer.adjust(lastWasCR);
    123      lastWasCR = false;
    124      if (buffer.hasMore()) {
    125        if (!mTokenizer->EnsureBufferSpace(buffer.getLength())) {
    126          rv = mBuilder->MarkAsBroken(NS_ERROR_OUT_OF_MEMORY);
    127          break;
    128        }
    129        lastWasCR = mTokenizer->tokenizeBuffer(&buffer);
    130        if (NS_FAILED(rv = mBuilder->IsBroken())) {
    131          break;
    132        }
    133      }
    134    }
    135  }
    136  if (NS_SUCCEEDED(rv)) {
    137    mTokenizer->eof();
    138  }
    139 
    140  mTokenizer->end();
    141  mBuilder->Finish();
    142  mAtomTable.Clear();
    143  TryCache();
    144  return rv;
    145 }