tor-browser

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

nsContentSink.cpp (31970B)


      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 /*
      8 * Base class for the XML and HTML content sinks, which construct a
      9 * DOM based on information from the parser.
     10 */
     11 
     12 #include "nsContentSink.h"
     13 
     14 #include <stdint.h>
     15 
     16 #include "HTMLLinkElement.h"
     17 #include "Link.h"
     18 #include "MediaList.h"
     19 #include "mozAutoDocUpdate.h"
     20 #include "mozilla/Components.h"
     21 #include "mozilla/Preferences.h"
     22 #include "mozilla/PresShell.h"
     23 #include "mozilla/PresShellWidgetListener.h"
     24 #include "mozilla/ProfilerLabels.h"
     25 #include "mozilla/RefPtr.h"
     26 #include "mozilla/StaticPrefs_browser.h"
     27 #include "mozilla/StaticPrefs_content.h"
     28 #include "mozilla/StaticPrefs_network.h"
     29 #include "mozilla/StoragePrincipalHelper.h"
     30 #include "mozilla/css/Loader.h"
     31 #include "mozilla/dom/Document.h"
     32 #include "mozilla/dom/HTMLDNSPrefetch.h"
     33 #include "mozilla/dom/LinkStyle.h"
     34 #include "mozilla/dom/MutationObservers.h"
     35 #include "mozilla/dom/ReferrerInfo.h"
     36 #include "mozilla/dom/SRILogHelper.h"
     37 #include "mozilla/dom/ScriptLoader.h"
     38 #include "mozilla/dom/ServiceWorkerDescriptor.h"
     39 #include "mozilla/net/HttpBaseChannel.h"
     40 #include "mozilla/net/NeckoChannelParams.h"
     41 #include "nsAtom.h"
     42 #include "nsCOMPtr.h"
     43 #include "nsContentUtils.h"
     44 #include "nsGenericHTMLElement.h"
     45 #include "nsGkAtoms.h"
     46 #include "nsGlobalWindowInner.h"
     47 #include "nsIAppShell.h"
     48 #include "nsIContent.h"
     49 #include "nsIContentPolicy.h"
     50 #include "nsICookieService.h"
     51 #include "nsIDocShell.h"
     52 #include "nsIHttpChannel.h"
     53 #include "nsILoadContext.h"
     54 #include "nsIMIMEHeaderParam.h"
     55 #include "nsIObserverService.h"
     56 #include "nsIPrefetchService.h"
     57 #include "nsIProtocolHandler.h"
     58 #include "nsIURI.h"
     59 #include "nsIWebNavigation.h"
     60 #include "nsIWidget.h"
     61 #include "nsLiteralString.h"
     62 #include "nsNetCID.h"
     63 #include "nsNetUtil.h"
     64 #include "nsNodeInfoManager.h"
     65 #include "nsParserConstants.h"
     66 #include "nsPresContext.h"
     67 #include "nsSandboxFlags.h"
     68 #include "nsString.h"
     69 #include "nsStringFwd.h"
     70 #include "nsWidgetsCID.h"
     71 using namespace mozilla;
     72 using namespace mozilla::css;
     73 using namespace mozilla::dom;
     74 
     75 LazyLogModule gContentSinkLogModuleInfo("nscontentsink");
     76 
     77 NS_IMPL_CYCLE_COLLECTING_ADDREF(nsContentSink)
     78 NS_IMPL_CYCLE_COLLECTING_RELEASE(nsContentSink)
     79 
     80 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(nsContentSink)
     81  NS_INTERFACE_MAP_ENTRY(nsICSSLoaderObserver)
     82  NS_INTERFACE_MAP_ENTRY(nsISupportsWeakReference)
     83  NS_INTERFACE_MAP_ENTRY(nsIDocumentObserver)
     84  NS_INTERFACE_MAP_ENTRY(nsIMutationObserver)
     85  NS_INTERFACE_MAP_ENTRY(nsITimerCallback)
     86  NS_INTERFACE_MAP_ENTRY(nsINamed)
     87  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIDocumentObserver)
     88 NS_INTERFACE_MAP_END
     89 
     90 NS_IMPL_CYCLE_COLLECTION_CLASS(nsContentSink)
     91 
     92 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(nsContentSink)
     93  if (tmp->mDocument) {
     94    tmp->mDocument->RemoveObserver(tmp);
     95  }
     96  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocument)
     97  NS_IMPL_CYCLE_COLLECTION_UNLINK(mParser)
     98  NS_IMPL_CYCLE_COLLECTION_UNLINK(mDocShell)
     99  NS_IMPL_CYCLE_COLLECTION_UNLINK(mNodeInfoManager)
    100  NS_IMPL_CYCLE_COLLECTION_UNLINK(mScriptLoader)
    101  NS_IMPL_CYCLE_COLLECTION_UNLINK_WEAK_REFERENCE
    102 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
    103 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(nsContentSink)
    104  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocument)
    105  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mParser)
    106  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mDocShell)
    107  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mNodeInfoManager)
    108  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mScriptLoader)
    109 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
    110 
    111 nsContentSink::nsContentSink()
    112    : mBackoffCount(0),
    113      mLastNotificationTime(0),
    114      mLayoutStarted(0),
    115      mDynamicLowerValue(0),
    116      mParsing(0),
    117      mDroppedTimer(0),
    118      mDeferredLayoutStart(0),
    119      mDeferredFlushTags(0),
    120      mIsDocumentObserver(0),
    121      mRunsToCompletion(0),
    122      mIsBlockingOnload(false),
    123      mDeflectedCount(0),
    124      mHasPendingEvent(false),
    125      mCurrentParseEndTime(0),
    126      mBeginLoadTime(0),
    127      mLastSampledUserEventTime(0),
    128      mInMonolithicContainer(0),
    129      mInNotification(0),
    130      mUpdatesInNotification(0),
    131      mPendingSheetCount(0) {
    132  NS_ASSERTION(!mLayoutStarted, "What?");
    133  NS_ASSERTION(!mDynamicLowerValue, "What?");
    134  NS_ASSERTION(!mParsing, "What?");
    135  NS_ASSERTION(mLastSampledUserEventTime == 0, "What?");
    136  NS_ASSERTION(mDeflectedCount == 0, "What?");
    137  NS_ASSERTION(!mDroppedTimer, "What?");
    138  NS_ASSERTION(mInMonolithicContainer == 0, "What?");
    139  NS_ASSERTION(mInNotification == 0, "What?");
    140  NS_ASSERTION(!mDeferredLayoutStart, "What?");
    141 }
    142 
    143 nsContentSink::~nsContentSink() {
    144  if (mDocument) {
    145    // Remove ourselves just to be safe, though we really should have
    146    // been removed in DidBuildModel if everything worked right.
    147    mDocument->RemoveObserver(this);
    148  }
    149 }
    150 
    151 nsresult nsContentSink::Init(Document* aDoc, nsIURI* aURI,
    152                             nsISupports* aContainer, nsIChannel* aChannel) {
    153  MOZ_ASSERT(aDoc, "null ptr");
    154  MOZ_ASSERT(aURI, "null ptr");
    155 
    156  if (!aDoc || !aURI) {
    157    return NS_ERROR_NULL_POINTER;
    158  }
    159 
    160  mDocument = aDoc;
    161 
    162  mDocumentURI = aURI;
    163  mDocShell = do_QueryInterface(aContainer);
    164  mScriptLoader = mDocument->GetScriptLoader();
    165 
    166  if (!mRunsToCompletion) {
    167    if (mDocShell) {
    168      uint32_t loadType = 0;
    169      mDocShell->GetLoadType(&loadType);
    170      mDocument->SetChangeScrollPosWhenScrollingToRef(
    171          (loadType & nsIDocShell::LOAD_CMD_HISTORY) == 0);
    172    }
    173 
    174    ProcessHTTPHeaders(aChannel);
    175  }
    176 
    177  mNodeInfoManager = aDoc->NodeInfoManager();
    178 
    179  mBackoffCount = StaticPrefs::content_notify_backoffcount();
    180 
    181  if (StaticPrefs::content_sink_enable_perf_mode() != 0) {
    182    mDynamicLowerValue = StaticPrefs::content_sink_enable_perf_mode() == 1;
    183  }
    184 
    185  return NS_OK;
    186 }
    187 
    188 NS_IMETHODIMP
    189 nsContentSink::StyleSheetLoaded(StyleSheet* aSheet, bool aWasDeferred,
    190                                nsresult aStatus) {
    191  MOZ_ASSERT(!mRunsToCompletion, "How come a fragment parser observed sheets?");
    192  if (aWasDeferred) {
    193    return NS_OK;
    194  }
    195  MOZ_ASSERT(mPendingSheetCount > 0, "How'd that happen?");
    196  --mPendingSheetCount;
    197 
    198  const bool loadedAllSheets = !mPendingSheetCount;
    199  if (loadedAllSheets && (mDeferredLayoutStart || mDeferredFlushTags)) {
    200    if (mDeferredFlushTags) {
    201      FlushTags();
    202    }
    203    if (mDeferredLayoutStart) {
    204      // We might not have really started layout, since this sheet was still
    205      // loading.  Do it now.  Probably doesn't matter whether we do this
    206      // before or after we unblock scripts, but before feels saner.  Note
    207      // that if mDeferredLayoutStart is true, that means any subclass
    208      // StartLayout() stuff that needs to happen has already happened, so
    209      // we don't need to worry about it.
    210      StartLayout(false);
    211    }
    212 
    213    // Go ahead and try to scroll to our ref if we have one
    214    ScrollToRef();
    215  }
    216 
    217  if (mScriptLoader) {
    218    mScriptLoader->RemoveParserBlockingScriptExecutionBlocker();
    219 
    220    if (loadedAllSheets &&
    221        mDocument->GetReadyStateEnum() >= Document::READYSTATE_INTERACTIVE) {
    222      mScriptLoader->DeferCheckpointReached();
    223    }
    224  }
    225 
    226  return NS_OK;
    227 }
    228 
    229 nsresult nsContentSink::ProcessHTTPHeaders(nsIChannel* aChannel) {
    230  nsCOMPtr<nsIHttpChannel> httpchannel(do_QueryInterface(aChannel));
    231 
    232  if (!httpchannel) {
    233    return NS_OK;
    234  }
    235 
    236  bool gotEarlyHints = false;
    237  if (nsCOMPtr<mozilla::net::HttpBaseChannel> baseChannel =
    238          do_QueryInterface(aChannel)) {
    239    nsTArray<mozilla::net::EarlyHintConnectArgs> earlyHints =
    240        baseChannel->TakeEarlyHints();
    241    gotEarlyHints = !earlyHints.IsEmpty();
    242    mDocument->SetEarlyHints(std::move(earlyHints));
    243  }
    244 
    245  // Note that the only header we care about is the "link" header, since we
    246  // have all the infrastructure for kicking off stylesheet loads.
    247 
    248  nsAutoCString linkHeader;
    249 
    250  nsresult rv = httpchannel->GetResponseHeader("link"_ns, linkHeader);
    251  bool gotLinkHeader = NS_SUCCEEDED(rv) && !linkHeader.IsEmpty();
    252  if (gotLinkHeader) {
    253    mDocument->SetHeaderData(nsGkAtoms::link,
    254                             NS_ConvertASCIItoUTF16(linkHeader));
    255  }
    256  if (gotLinkHeader || gotEarlyHints) {
    257    NS_ASSERTION(!mProcessLinkHeaderEvent.get(),
    258                 "Already dispatched an event?");
    259 
    260    mProcessLinkHeaderEvent =
    261        NewNonOwningRunnableMethod("nsContentSink::DoProcessLinkHeader", this,
    262                                   &nsContentSink::DoProcessLinkHeader);
    263    rv = NS_DispatchToCurrentThread(mProcessLinkHeaderEvent.get());
    264    if (NS_FAILED(rv)) {
    265      mProcessLinkHeaderEvent.Forget();
    266    }
    267  }
    268 
    269  return NS_OK;
    270 }
    271 
    272 void nsContentSink::DoProcessLinkHeader() {
    273  for (const auto& earlyHint : mDocument->GetEarlyHints()) {
    274    ProcessLinkFromHeader(earlyHint.link(), earlyHint.earlyHintPreloaderId());
    275  }
    276 
    277  nsAutoString value;
    278 
    279  // Getting the header data and parsing the link header together roughly
    280  // implement <https://httpwg.org/specs/rfc8288.html#parse-set>.
    281  mDocument->GetHeaderData(nsGkAtoms::link, value);
    282  auto linkHeaders = net::ParseLinkHeader(value);
    283 
    284  for (const auto& linkHeader : linkHeaders) {
    285    ProcessLinkFromHeader(linkHeader, 0);
    286  }
    287 }
    288 
    289 nsresult nsContentSink::ProcessLinkFromHeader(const net::LinkHeader& aHeader,
    290                                              uint64_t aEarlyHintPreloaderId) {
    291  uint32_t linkTypes = LinkStyle::ParseLinkTypes(aHeader.mRel);
    292 
    293  // The link relation may apply to a different resource, specified
    294  // in the anchor parameter. For the link relations supported so far,
    295  // we simply abort if the link applies to a resource different to the
    296  // one we've loaded
    297  if (!nsContentUtils::LinkContextIsURI(aHeader.mAnchor,
    298                                        mDocument->GetDocumentURI())) {
    299    return NS_OK;
    300  }
    301 
    302  if (nsContentUtils::PrefetchPreloadEnabled(mDocShell)) {
    303    // prefetch href if relation is "next" or "prefetch"
    304    if ((linkTypes & LinkStyle::eNEXT) || (linkTypes & LinkStyle::ePREFETCH)) {
    305      PrefetchHref(aHeader.mHref, aHeader.mAs, aHeader.mType, aHeader.mMedia);
    306    }
    307 
    308    if (!aHeader.mHref.IsEmpty() && (linkTypes & LinkStyle::eDNS_PREFETCH)) {
    309      PrefetchDNS(aHeader.mHref);
    310    }
    311 
    312    if (!aHeader.mHref.IsEmpty() && (linkTypes & LinkStyle::ePRECONNECT)) {
    313      Preconnect(aHeader.mHref, aHeader.mCrossOrigin);
    314    }
    315 
    316    if (linkTypes & LinkStyle::ePRELOAD) {
    317      PreloadHref(aHeader.mHref, aHeader.mAs, aHeader.mRel, aHeader.mType,
    318                  aHeader.mMedia, aHeader.mNonce, aHeader.mIntegrity,
    319                  aHeader.mSrcset, aHeader.mSizes, aHeader.mCrossOrigin,
    320                  aHeader.mReferrerPolicy, aEarlyHintPreloaderId,
    321                  aHeader.mFetchPriority);
    322    }
    323 
    324    if (linkTypes & LinkStyle::eCOMPRESSION_DICTIONARY) {
    325      PreloadHref(aHeader.mHref, u"fetch"_ns, aHeader.mRel, aHeader.mType,
    326                  aHeader.mMedia, aHeader.mNonce, aHeader.mIntegrity,
    327                  aHeader.mSrcset, aHeader.mSizes, aHeader.mCrossOrigin,
    328                  aHeader.mReferrerPolicy, aEarlyHintPreloaderId,
    329                  aHeader.mFetchPriority);
    330    }
    331 
    332    if ((linkTypes & LinkStyle::eMODULE_PRELOAD) &&
    333        mDocument->GetScriptLoader() &&
    334        mDocument->GetScriptLoader()->GetModuleLoader()) {
    335      PreloadModule(aHeader.mHref, aHeader.mAs, aHeader.mMedia, aHeader.mNonce,
    336                    aHeader.mIntegrity, aHeader.mCrossOrigin,
    337                    aHeader.mReferrerPolicy, aEarlyHintPreloaderId,
    338                    aHeader.mFetchPriority);
    339    }
    340  }
    341 
    342  // is it a stylesheet link?
    343  if (!(linkTypes & LinkStyle::eSTYLESHEET)) {
    344    return NS_OK;
    345  }
    346 
    347  bool isAlternate = linkTypes & LinkStyle::eALTERNATE;
    348  return ProcessStyleLinkFromHeader(aHeader.mHref, isAlternate, aHeader.mTitle,
    349                                    aHeader.mIntegrity, aHeader.mType,
    350                                    aHeader.mMedia, aHeader.mReferrerPolicy,
    351                                    aHeader.mFetchPriority);
    352 }
    353 
    354 nsresult nsContentSink::ProcessStyleLinkFromHeader(
    355    const nsAString& aHref, bool aAlternate, const nsAString& aTitle,
    356    const nsAString& aIntegrity, const nsAString& aType,
    357    const nsAString& aMedia, const nsAString& aReferrerPolicy,
    358    const nsAString& aFetchPriority) {
    359  if (aAlternate && aTitle.IsEmpty()) {
    360    // alternates must have title return without error, for now
    361    return NS_OK;
    362  }
    363 
    364  nsAutoString mimeType;
    365  nsAutoString params;
    366  nsContentUtils::SplitMimeType(aType, mimeType, params);
    367 
    368  // see bug 18817
    369  if (!mimeType.IsEmpty() && !mimeType.LowerCaseEqualsLiteral("text/css")) {
    370    // Unknown stylesheet language
    371    return NS_OK;
    372  }
    373 
    374  nsCOMPtr<nsIURI> url;
    375  nsresult rv = NS_NewURI(getter_AddRefs(url), aHref, nullptr,
    376                          mDocument->GetDocBaseURI());
    377 
    378  if (NS_FAILED(rv)) {
    379    // The URI is bad, move along, don't propagate the error (for now)
    380    return NS_OK;
    381  }
    382 
    383  // Link header is working like a <link> node, so referrerPolicy attr should
    384  // have higher priority than referrer policy from document.
    385  ReferrerPolicy policy =
    386      ReferrerInfo::ReferrerPolicyAttributeFromString(aReferrerPolicy);
    387  nsCOMPtr<nsIReferrerInfo> referrerInfo =
    388      ReferrerInfo::CreateFromDocumentAndPolicyOverride(mDocument, policy);
    389 
    390  const FetchPriority fetchPriority =
    391      nsGenericHTMLElement::ToFetchPriority(aFetchPriority);
    392 
    393  Loader::SheetInfo info{
    394      *mDocument,
    395      nullptr,
    396      url.forget(),
    397      nullptr,
    398      referrerInfo.forget(),
    399      CORS_NONE,
    400      aTitle,
    401      aMedia,
    402      aIntegrity,
    403      /* nonce = */ u""_ns,
    404      aAlternate ? Loader::HasAlternateRel::Yes : Loader::HasAlternateRel::No,
    405      Loader::IsInline::No,
    406      Loader::IsExplicitlyEnabled::No,
    407      fetchPriority,
    408  };
    409 
    410  auto loadResultOrErr = mDocument->EnsureCSSLoader().LoadStyleLink(
    411      info, mRunsToCompletion ? nullptr : this);
    412  if (loadResultOrErr.isErr()) {
    413    return loadResultOrErr.unwrapErr();
    414  }
    415 
    416  if (loadResultOrErr.inspect().ShouldBlock() && !mRunsToCompletion) {
    417    ++mPendingSheetCount;
    418    if (mScriptLoader) {
    419      mScriptLoader->AddParserBlockingScriptExecutionBlocker();
    420    }
    421  }
    422 
    423  return NS_OK;
    424 }
    425 
    426 void nsContentSink::PrefetchHref(const nsAString& aHref, const nsAString& aAs,
    427                                 const nsAString& aType,
    428                                 const nsAString& aMedia) {
    429  nsCOMPtr<nsIPrefetchService> prefetchService(components::Prefetch::Service());
    430  if (prefetchService) {
    431    // construct URI using document charset
    432    auto encoding = mDocument->GetDocumentCharacterSet();
    433    nsCOMPtr<nsIURI> uri;
    434    NS_NewURI(getter_AddRefs(uri), aHref, encoding, mDocument->GetDocBaseURI());
    435    if (uri) {
    436      auto referrerInfo = MakeRefPtr<ReferrerInfo>(*mDocument);
    437      referrerInfo = referrerInfo->CloneWithNewOriginalReferrer(mDocumentURI);
    438 
    439      prefetchService->PrefetchURI(uri, referrerInfo, mDocument, true);
    440    }
    441  }
    442 }
    443 
    444 void nsContentSink::PreloadHref(
    445    const nsAString& aHref, const nsAString& aAs, const nsAString& aRel,
    446    const nsAString& aType, const nsAString& aMedia, const nsAString& aNonce,
    447    const nsAString& aIntegrity, const nsAString& aSrcset,
    448    const nsAString& aSizes, const nsAString& aCORS,
    449    const nsAString& aReferrerPolicy, uint64_t aEarlyHintPreloaderId,
    450    const nsAString& aFetchPriority) {
    451  auto encoding = mDocument->GetDocumentCharacterSet();
    452  nsCOMPtr<nsIURI> uri;
    453  NS_NewURI(getter_AddRefs(uri), aHref, encoding, mDocument->GetDocBaseURI());
    454  if (!uri) {
    455    // URL parsing failed.
    456    return;
    457  }
    458 
    459  nsAttrValue asAttr;
    460  mozilla::net::ParseAsValue(aAs, asAttr);
    461 
    462  nsAutoString mimeType;
    463  nsAutoString notUsed;
    464  nsContentUtils::SplitMimeType(aType, mimeType, notUsed);
    465 
    466  auto policyType = mozilla::net::AsValueToContentPolicy(asAttr);
    467  if (policyType == nsIContentPolicy::TYPE_INVALID ||
    468      !mozilla::net::CheckPreloadAttrs(asAttr, mimeType, aMedia, mDocument)) {
    469    // Ignore preload wrong or empty attributes.
    470    mozilla::net::WarnIgnoredPreload(*mDocument, *uri);
    471    return;
    472  }
    473 
    474  mDocument->Preloads().PreloadLinkHeader(
    475      uri, aHref, policyType, aAs, aRel, aType, aNonce, aIntegrity, aSrcset,
    476      aSizes, aCORS, aReferrerPolicy, aEarlyHintPreloaderId, aFetchPriority);
    477 }
    478 
    479 void nsContentSink::PreloadModule(
    480    const nsAString& aHref, const nsAString& aAs, const nsAString& aMedia,
    481    const nsAString& aNonce, const nsAString& aIntegrity,
    482    const nsAString& aCORS, const nsAString& aReferrerPolicy,
    483    uint64_t aEarlyHintPreloaderId, const nsAString& aFetchPriority) {
    484  dom::ScriptLoader* scriptLoader = mDocument->GetScriptLoader();
    485  if (!scriptLoader) {
    486    return;
    487  }
    488  ModuleLoader* moduleLoader = scriptLoader->GetModuleLoader();
    489 
    490  if (!StaticPrefs::network_modulepreload()) {
    491    // Keep behavior from https://phabricator.services.mozilla.com/D149371,
    492    // prior to main implementation of modulepreload
    493    moduleLoader->DisallowImportMaps();
    494    return;
    495  }
    496 
    497  RefPtr<mozilla::dom::MediaList> mediaList =
    498      mozilla::dom::MediaList::Create(NS_ConvertUTF16toUTF8(aMedia));
    499  if (!mediaList->Matches(*mDocument)) {
    500    return;
    501  }
    502 
    503  if (aHref.IsEmpty()) {
    504    return;
    505  }
    506 
    507  if (!net::IsScriptLikeOrInvalid(aAs)) {
    508    return;
    509  }
    510 
    511  auto encoding = mDocument->GetDocumentCharacterSet();
    512  nsCOMPtr<nsIURI> uri;
    513  NS_NewURI(getter_AddRefs(uri), aHref, encoding, mDocument->GetDocBaseURI());
    514  if (!uri) {
    515    return;
    516  }
    517 
    518  moduleLoader->DisallowImportMaps();
    519 
    520  mDocument->Preloads().PreloadLinkHeader(
    521      uri, aHref, nsIContentPolicy::TYPE_SCRIPT, u"script"_ns,
    522      u"modulepreload"_ns, u"module"_ns, aNonce, aIntegrity, u""_ns, u""_ns,
    523      aCORS, aReferrerPolicy, aEarlyHintPreloaderId, aFetchPriority);
    524 }
    525 
    526 void nsContentSink::PrefetchDNS(const nsAString& aHref) {
    527  nsAutoString hostname;
    528  bool isHttps = false;
    529 
    530  if (StringBeginsWith(aHref, u"//"_ns)) {
    531    hostname = Substring(aHref, 2);
    532  } else {
    533    nsCOMPtr<nsIURI> uri;
    534    NS_NewURI(getter_AddRefs(uri), aHref);
    535    if (!uri) {
    536      return;
    537    }
    538    nsresult rv;
    539    bool isLocalResource = false;
    540    rv = NS_URIChainHasFlags(uri, nsIProtocolHandler::URI_IS_LOCAL_RESOURCE,
    541                             &isLocalResource);
    542    if (NS_SUCCEEDED(rv) && !isLocalResource) {
    543      nsAutoCString host;
    544      uri->GetHost(host);
    545      CopyUTF8toUTF16(host, hostname);
    546    }
    547    isHttps = uri->SchemeIs("https");
    548  }
    549 
    550  if (!hostname.IsEmpty() && HTMLDNSPrefetch::IsAllowed(mDocument)) {
    551    OriginAttributes oa;
    552    StoragePrincipalHelper::GetOriginAttributesForNetworkState(mDocument, oa);
    553 
    554    HTMLDNSPrefetch::Prefetch(hostname, isHttps, oa,
    555                              mDocument->GetChannel()->GetTRRMode(),
    556                              HTMLDNSPrefetch::Priority::Low);
    557  }
    558 }
    559 
    560 void nsContentSink::Preconnect(const nsAString& aHref,
    561                               const nsAString& aCrossOrigin) {
    562  // construct URI using document charset
    563  auto encoding = mDocument->GetDocumentCharacterSet();
    564  nsCOMPtr<nsIURI> uri;
    565  NS_NewURI(getter_AddRefs(uri), aHref, encoding, mDocument->GetDocBaseURI());
    566 
    567  if (uri && mDocument) {
    568    mDocument->MaybePreconnect(uri,
    569                               dom::Element::StringToCORSMode(aCrossOrigin));
    570  }
    571 }
    572 
    573 void nsContentSink::ScrollToRef() {
    574  RefPtr<Document> document = mDocument;
    575  document->ScrollToRef();
    576 }
    577 
    578 void nsContentSink::StartLayout(bool aIgnorePendingSheets) {
    579  if (mLayoutStarted) {
    580    // Nothing to do here
    581    return;
    582  }
    583 
    584  mDeferredLayoutStart = true;
    585 
    586  if (!aIgnorePendingSheets &&
    587      (WaitForPendingSheets() || mDocument->HasPendingInitialTranslation())) {
    588    // Bail out; we'll start layout when the sheets and l10n load
    589    return;
    590  }
    591 
    592  AUTO_PROFILER_LABEL_DYNAMIC_NSCSTRING_RELEVANT_FOR_JS(
    593      "Layout", LAYOUT, mDocumentURI->GetSpecOrDefault());
    594 
    595  mDeferredLayoutStart = false;
    596 
    597  if (aIgnorePendingSheets) {
    598    nsContentUtils::ReportToConsole(
    599        nsIScriptError::warningFlag, "Layout"_ns, mDocument,
    600        nsContentUtils::eLAYOUT_PROPERTIES, "ForcedLayoutStart");
    601  }
    602 
    603  // Notify on all our content.  If none of our presshells have started layout
    604  // yet it'll be a no-op except for updating our data structures, a la
    605  // UpdateChildCounts() (because we don't want to double-notify on whatever we
    606  // have right now).  If some of them _have_ started layout, we want to make
    607  // sure to flush tags instead of just calling UpdateChildCounts() after we
    608  // loop over the shells.
    609  FlushTags();
    610 
    611  mLayoutStarted = true;
    612  mLastNotificationTime = PR_Now();
    613 
    614  mDocument->SetMayStartLayout(true);
    615  RefPtr<PresShell> presShell = mDocument->GetPresShell();
    616  // Make sure we don't call Initialize() for a shell that has
    617  // already called it. This can happen when the layout frame for
    618  // an iframe is constructed *between* the Embed() call for the
    619  // docshell in the iframe, and the content sink's call to OpenBody().
    620  // (Bug 153815)
    621  if (presShell && !presShell->DidInitialize()) {
    622    nsresult rv = presShell->Initialize();
    623    if (NS_FAILED(rv)) {
    624      return;
    625    }
    626  }
    627 
    628  // If the document we are loading has a reference or it is a
    629  // frameset document, disable the scroll bars on the views.
    630 
    631  mDocument->SetScrollToRef(mDocument->GetDocumentURI());
    632 }
    633 
    634 void nsContentSink::NotifyAppend(nsIContent* aContainer, uint32_t aStartIndex) {
    635  mInNotification++;
    636 
    637  {
    638    // Scope so we call EndUpdate before we decrease mInNotification
    639    //
    640    // Note that aContainer->OwnerDoc() may not be mDocument.
    641    MOZ_AUTO_DOC_UPDATE(aContainer->OwnerDoc(), true);
    642    MutationObservers::NotifyContentAppended(
    643        aContainer, aContainer->GetChildAt_Deprecated(aStartIndex), {});
    644    mLastNotificationTime = PR_Now();
    645  }
    646 
    647  mInNotification--;
    648 }
    649 
    650 NS_IMETHODIMP
    651 nsContentSink::Notify(nsITimer* timer) {
    652  if (mParsing) {
    653    // We shouldn't interfere with our normal DidProcessAToken logic
    654    mDroppedTimer = true;
    655    return NS_OK;
    656  }
    657 
    658  if (WaitForPendingSheets()) {
    659    mDeferredFlushTags = true;
    660  } else {
    661    FlushTags();
    662 
    663    // Now try and scroll to the reference
    664    // XXX Should we scroll unconditionally for history loads??
    665    ScrollToRef();
    666  }
    667 
    668  mNotificationTimer = nullptr;
    669  return NS_OK;
    670 }
    671 
    672 bool nsContentSink::IsTimeToNotify() {
    673  if (!StaticPrefs::content_notify_ontimer() || !mLayoutStarted ||
    674      !mBackoffCount || mInMonolithicContainer) {
    675    return false;
    676  }
    677 
    678  if (WaitForPendingSheets()) {
    679    mDeferredFlushTags = true;
    680    return false;
    681  }
    682 
    683  PRTime now = PR_Now();
    684 
    685  int64_t interval = GetNotificationInterval();
    686  int64_t diff = now - mLastNotificationTime;
    687 
    688  if (diff > interval) {
    689    mBackoffCount--;
    690    return true;
    691  }
    692 
    693  return false;
    694 }
    695 
    696 nsresult nsContentSink::WillInterruptImpl() {
    697  nsresult result = NS_OK;
    698 
    699  SINK_TRACE(static_cast<LogModule*>(gContentSinkLogModuleInfo),
    700             SINK_TRACE_CALLS, ("nsContentSink::WillInterrupt: this=%p", this));
    701 #ifndef SINK_NO_INCREMENTAL
    702  if (WaitForPendingSheets()) {
    703    mDeferredFlushTags = true;
    704  } else if (StaticPrefs::content_notify_ontimer() && mLayoutStarted) {
    705    if (mBackoffCount && !mInMonolithicContainer) {
    706      int64_t now = PR_Now();
    707      int64_t interval = GetNotificationInterval();
    708      int64_t diff = now - mLastNotificationTime;
    709 
    710      // If it's already time for us to have a notification
    711      if (diff > interval || mDroppedTimer) {
    712        mBackoffCount--;
    713        SINK_TRACE(static_cast<LogModule*>(gContentSinkLogModuleInfo),
    714                   SINK_TRACE_REFLOW,
    715                   ("nsContentSink::WillInterrupt: flushing tags since we've "
    716                    "run out time; backoff count: %d",
    717                    mBackoffCount));
    718        result = FlushTags();
    719        if (mDroppedTimer) {
    720          ScrollToRef();
    721          mDroppedTimer = false;
    722        }
    723      } else if (!mNotificationTimer) {
    724        interval -= diff;
    725        int32_t delay = interval;
    726 
    727        // Convert to milliseconds
    728        delay /= PR_USEC_PER_MSEC;
    729 
    730        NS_NewTimerWithCallback(getter_AddRefs(mNotificationTimer), this, delay,
    731                                nsITimer::TYPE_ONE_SHOT);
    732        if (mNotificationTimer) {
    733          SINK_TRACE(static_cast<LogModule*>(gContentSinkLogModuleInfo),
    734                     SINK_TRACE_REFLOW,
    735                     ("nsContentSink::WillInterrupt: setting up timer with "
    736                      "delay %d",
    737                      delay));
    738        }
    739      }
    740    }
    741  } else {
    742    SINK_TRACE(static_cast<LogModule*>(gContentSinkLogModuleInfo),
    743               SINK_TRACE_REFLOW,
    744               ("nsContentSink::WillInterrupt: flushing tags "
    745                "unconditionally"));
    746    result = FlushTags();
    747  }
    748 #endif
    749 
    750  mParsing = false;
    751 
    752  return result;
    753 }
    754 
    755 void nsContentSink::WillResumeImpl() {
    756  SINK_TRACE(static_cast<LogModule*>(gContentSinkLogModuleInfo),
    757             SINK_TRACE_CALLS, ("nsContentSink::WillResume: this=%p", this));
    758 
    759  mParsing = true;
    760 }
    761 
    762 nsresult nsContentSink::DidProcessATokenImpl() {
    763  if (mRunsToCompletion || !mParser) {
    764    return NS_OK;
    765  }
    766 
    767  // Get the current user event time
    768  PresShell* presShell = mDocument->GetPresShell();
    769  if (!presShell) {
    770    // If there's no pres shell in the document, return early since
    771    // we're not laying anything out here.
    772    return NS_OK;
    773  }
    774 
    775  // Increase before comparing to gEventProbeRate
    776  ++mDeflectedCount;
    777 
    778  // Check if there's a pending event
    779  if (StaticPrefs::content_sink_pending_event_mode() != 0 &&
    780      !mHasPendingEvent &&
    781      (mDeflectedCount % StaticPrefs::content_sink_event_probe_rate()) == 0) {
    782    nsIWidget* widget = presShell->GetRootWidget();
    783    mHasPendingEvent = widget && widget->HasPendingInputEvent();
    784  }
    785 
    786  if (mHasPendingEvent && StaticPrefs::content_sink_pending_event_mode() == 2) {
    787    return NS_ERROR_HTMLPARSER_INTERRUPTED;
    788  }
    789 
    790  // Have we processed enough tokens to check time?
    791  if (!mHasPendingEvent &&
    792      mDeflectedCount <
    793          uint32_t(mDynamicLowerValue
    794                       ? StaticPrefs::content_sink_interactive_deflect_count()
    795                       : StaticPrefs::content_sink_perf_deflect_count())) {
    796    return NS_OK;
    797  }
    798 
    799  mDeflectedCount = 0;
    800 
    801  // Check if it's time to return to the main event loop
    802  if (PR_IntervalToMicroseconds(PR_IntervalNow()) > mCurrentParseEndTime) {
    803    return NS_ERROR_HTMLPARSER_INTERRUPTED;
    804  }
    805 
    806  return NS_OK;
    807 }
    808 
    809 //----------------------------------------------------------------------
    810 
    811 void nsContentSink::BeginUpdate(Document* aDocument) {
    812  // Remember nested updates from updates that we started.
    813  if (mInNotification > 0 && mUpdatesInNotification < 2) {
    814    ++mUpdatesInNotification;
    815  }
    816 
    817  // If we're in a script and we didn't do the notification,
    818  // something else in the script processing caused the
    819  // notification to occur. Since this could result in frame
    820  // creation, make sure we've flushed everything before we
    821  // continue.
    822 
    823  if (!mInNotification++) {
    824    FlushTags();
    825  }
    826 }
    827 
    828 void nsContentSink::EndUpdate(Document* aDocument) {
    829  // If we're in a script and we didn't do the notification,
    830  // something else in the script processing caused the
    831  // notification to occur. Update our notion of how much
    832  // has been flushed to include any new content if ending
    833  // this update leaves us not inside a notification.
    834  if (!--mInNotification) {
    835    UpdateChildCounts();
    836  }
    837 }
    838 
    839 void nsContentSink::DidBuildModelImpl(bool aTerminated) {
    840  MOZ_ASSERT(aTerminated || (mParser && mParser->IsParserClosed()) ||
    841                 mDocument->GetReadyStateEnum() == Document::READYSTATE_LOADING,
    842             "Bad readyState");
    843  mDocument->SetReadyStateInternal(Document::READYSTATE_INTERACTIVE);
    844 
    845  if (mScriptLoader) {
    846    mScriptLoader->ParsingComplete(aTerminated);
    847    if (!mPendingSheetCount) {
    848      mScriptLoader->DeferCheckpointReached();
    849    }
    850  }
    851 
    852  if (!mDocument->HaveFiredDOMTitleChange()) {
    853    mDocument->NotifyPossibleTitleChange(false);
    854  }
    855 
    856  // Cancel a timer if we had one out there
    857  if (mNotificationTimer) {
    858    SINK_TRACE(static_cast<LogModule*>(gContentSinkLogModuleInfo),
    859               SINK_TRACE_REFLOW,
    860               ("nsContentSink::DidBuildModel: canceling notification "
    861                "timeout"));
    862    mNotificationTimer->Cancel();
    863    mNotificationTimer = nullptr;
    864  }
    865 }
    866 
    867 void nsContentSink::DropParserAndPerfHint(void) {
    868  if (!mParser) {
    869    // Make sure we don't unblock unload too many times
    870    return;
    871  }
    872 
    873  // Ref. Bug 49115
    874  // Do this hack to make sure that the parser
    875  // doesn't get destroyed, accidently, before
    876  // the circularity, between sink & parser, is
    877  // actually broken.
    878  // Drop our reference to the parser to get rid of a circular
    879  // reference.
    880  RefPtr<nsParserBase> kungFuDeathGrip = std::move(mParser);
    881  (void)kungFuDeathGrip;
    882 
    883  // Call UnblockOnload only if mRunsToComletion is false and if
    884  // we have already started loading because it's possible that this function
    885  // is called (i.e. the parser is terminated) before we start loading due to
    886  // destroying the window inside unload event callbacks for the previous
    887  // document.
    888  if (!mRunsToCompletion && mIsBlockingOnload) {
    889    mDocument->UnblockOnload(true);
    890    mIsBlockingOnload = false;
    891  }
    892 }
    893 
    894 bool nsContentSink::IsScriptExecutingImpl() {
    895  return mScriptLoader && mScriptLoader->GetCurrentScript();
    896 }
    897 
    898 void nsContentSink::ContinueParsingDocumentAfterCurrentScriptImpl() {
    899  if (mScriptLoader) {
    900    mScriptLoader->ContinueParsingDocumentAfterCurrentScript();
    901  }
    902 }
    903 
    904 nsresult nsContentSink::WillParseImpl(void) {
    905  if (mRunsToCompletion || !mDocument) {
    906    return NS_OK;
    907  }
    908 
    909  PresShell* presShell = mDocument->GetPresShell();
    910  if (!presShell) {
    911    return NS_OK;
    912  }
    913 
    914  uint32_t currentTime = PR_IntervalToMicroseconds(PR_IntervalNow());
    915 
    916  if (StaticPrefs::content_sink_enable_perf_mode() == 0) {
    917    uint32_t lastEventTime = PresShellWidgetListener::GetLastUserEventTime();
    918    bool newDynLower = mDocument->IsInBackgroundWindow() ||
    919                       ((currentTime - mBeginLoadTime) >
    920                            StaticPrefs::content_sink_initial_perf_time() &&
    921                        (currentTime - lastEventTime) <
    922                            StaticPrefs::content_sink_interactive_time());
    923 
    924    if (mDynamicLowerValue != newDynLower) {
    925      mDynamicLowerValue = newDynLower;
    926    }
    927  }
    928 
    929  mDeflectedCount = 0;
    930  mHasPendingEvent = false;
    931 
    932  mCurrentParseEndTime =
    933      currentTime + (mDynamicLowerValue
    934                         ? StaticPrefs::content_sink_interactive_parse_time()
    935                         : StaticPrefs::content_sink_perf_parse_time());
    936 
    937  return NS_OK;
    938 }
    939 
    940 void nsContentSink::WillBuildModelImpl() {
    941  if (!mRunsToCompletion) {
    942    mDocument->BlockOnload();
    943    mIsBlockingOnload = true;
    944 
    945    mBeginLoadTime = PR_IntervalToMicroseconds(PR_IntervalNow());
    946  }
    947 
    948  mDocument->ResetScrolledToRefAlready();
    949 
    950  if (mProcessLinkHeaderEvent.get()) {
    951    mProcessLinkHeaderEvent.Revoke();
    952 
    953    DoProcessLinkHeader();
    954  }
    955 }
    956 
    957 /* static */
    958 void nsContentSink::NotifyDocElementCreated(Document* aDoc) {
    959  MOZ_ASSERT(nsContentUtils::IsSafeToRunScript());
    960 
    961  nsCOMPtr<nsIObserverService> observerService =
    962      mozilla::services::GetObserverService();
    963  MOZ_ASSERT(observerService);
    964 
    965  auto* win = nsGlobalWindowInner::Cast(aDoc->GetInnerWindow());
    966  bool fireInitialInsertion = !win || !win->DidFireDocElemInserted();
    967  if (win) {
    968    win->SetDidFireDocElemInserted();
    969  }
    970  if (fireInitialInsertion) {
    971    observerService->NotifyObservers(ToSupports(aDoc),
    972                                     "initial-document-element-inserted", u"");
    973  }
    974  observerService->NotifyObservers(ToSupports(aDoc),
    975                                   "document-element-inserted", u"");
    976 
    977  nsContentUtils::DispatchChromeEvent(aDoc, aDoc, u"DOMDocElementInserted"_ns,
    978                                      CanBubble::eYes, Cancelable::eNo);
    979 }
    980 
    981 NS_IMETHODIMP
    982 nsContentSink::GetName(nsACString& aName) {
    983  aName.AssignLiteral("nsContentSink_timer");
    984  return NS_OK;
    985 }