Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/uriloader/preload/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 13 kB image not shown  

Quelle  PreloadService.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "PreloadService.h"

#include "FetchPreloader.h"
#include "PreloaderBase.h"
#include "mozilla/Assertions.h"
#include "mozilla/AsyncEventDispatcher.h"
#include "mozilla/Maybe.h"
#include "mozilla/dom/FetchPriority.h"
#include "mozilla/dom/HTMLLinkElement.h"
#include "mozilla/dom/ScriptLoader.h"
#include "mozilla/dom/ReferrerInfo.h"
#include "mozilla/Encoding.h"
#include "mozilla/FontPreloader.h"
#include "mozilla/StaticPrefs_network.h"
#include "nsGenericHTMLElement.h"
#include "nsNetUtil.h"

namespace mozilla {

using namespace dom;

static LazyLogModule sPreloadServiceLog{"PreloadService"};

PreloadService::PreloadService(dom::Document* aDoc) : mDocument(aDoc) {}
PreloadService::~PreloadService() = default;

bool PreloadService::RegisterPreload(const PreloadHashKey& aKey,
                                     PreloaderBase* aPreload) {
  return mPreloads.WithEntryHandle(aKey, [&](auto&& lookup) {
    if (lookup) {
      lookup.Data() = aPreload;
      return true;
    }
    lookup.Insert(aPreload);
    return false;
  });
}

void PreloadService::DeregisterPreload(const PreloadHashKey& aKey) {
  mPreloads.Remove(aKey);
}

void PreloadService::ClearAllPreloads() { mPreloads.Clear(); }

bool PreloadService::PreloadExists(const PreloadHashKey& aKey) {
  return mPreloads.Contains(aKey);
}

already_AddRefed<PreloaderBase> PreloadService::LookupPreload(
    const PreloadHashKey& aKey) const {
  return mPreloads.Get(aKey);
}

already_AddRefed<nsIURI> PreloadService::GetPreloadURI(const nsAString& aURL) {
  nsIURI* base = BaseURIForPreload();
  auto encoding = mDocument->GetDocumentCharacterSet();

  nsCOMPtr<nsIURI> uri;
  nsresult rv = NS_NewURI(getter_AddRefs(uri), aURL, encoding, base);
  if (NS_FAILED(rv)) {
    return nullptr;
  }

  return uri.forget();
}

already_AddRefed<PreloaderBase> PreloadService::PreloadLinkElement(
    dom::HTMLLinkElement* aLinkElement, nsContentPolicyType aPolicyType) {
  if (aPolicyType == nsIContentPolicy::TYPE_INVALID) {
    MOZ_ASSERT_UNREACHABLE("Caller should check");
    return nullptr;
  }

  nsAutoString as, charset, crossOrigin, integrity, referrerPolicy,
      fetchPriority, rel, srcset, sizes, type, url;

  nsCOMPtr<nsIURI> uri = aLinkElement->GetURI();
  aLinkElement->GetCharset(charset);
  aLinkElement->GetImageSrcset(srcset);
  aLinkElement->GetImageSizes(sizes);
  aLinkElement->GetHref(url);
  aLinkElement->GetCrossOrigin(crossOrigin);
  aLinkElement->GetIntegrity(integrity);
  aLinkElement->GetReferrerPolicy(referrerPolicy);
  aLinkElement->GetFetchPriority(fetchPriority);
  aLinkElement->GetRel(rel);

  nsAutoString nonce;
  if (nsString* cspNonce =
          static_cast<nsString*>(aLinkElement->GetProperty(nsGkAtoms::nonce))) {
    nonce = *cspNonce;
  }

  if (rel.LowerCaseEqualsASCII("modulepreload")) {
    as = u"script"_ns;
    type = u"module"_ns;
  } else {
    aLinkElement->GetAs(as);
    aLinkElement->GetType(type);
  }

  auto result = PreloadOrCoalesce(uri, url, aPolicyType, as, type, charset,
                                  srcset, sizes, nonce, integrity, crossOrigin,
                                  referrerPolicy, fetchPriority,
                                  /* aFromHeader = */ false, 0);

  if (!result.mPreloader) {
    NotifyNodeEvent(aLinkElement, result.mAlreadyComplete);
    return nullptr;
  }

  result.mPreloader->AddLinkPreloadNode(aLinkElement);
  return result.mPreloader.forget();
}

void PreloadService::PreloadLinkHeader(
    nsIURI* aURI, const nsAString& aURL, nsContentPolicyType aPolicyType,
    const nsAString& aAs, const nsAString& aType, const nsAString& aNonce,
    const nsAString& aIntegrity, const nsAString& aSrcset,
    const nsAString& aSizes, const nsAString& aCORS,
    const nsAString& aReferrerPolicy, uint64_t aEarlyHintPreloaderId,
    const nsAString& aFetchPriority) {
  if (aPolicyType == nsIContentPolicy::TYPE_INVALID) {
    MOZ_ASSERT_UNREACHABLE("Caller should check");
    return;
  }

  PreloadOrCoalesce(aURI, aURL, aPolicyType, aAs, aType, u""_ns, aSrcset,
                    aSizes, aNonce, aIntegrity, aCORS, aReferrerPolicy,
                    aFetchPriority,
                    /* aFromHeader = */ true, aEarlyHintPreloaderId);
}

// The mapping is specified as implementation-defined, see step 15 of
// <https://fetch.spec.whatwg.org/#concept-fetch>.
// See corresponding preferences in StaticPrefList.yaml for more context.
class SupportsPriorityValueFor {
 public:
  static int32_t LinkRelPreloadFont(const FetchPriority aFetchPriority) {
    int32_t priorityValue = nsISupportsPriority::PRIORITY_HIGH;
    if (!StaticPrefs::network_fetchpriority_enabled()) {
      return priorityValue;
    }

    return priorityValue +
           FETCH_PRIORITY_ADJUSTMENT_FOR(link_preload_font, aFetchPriority);
  }

  static int32_t LinkRelPreloadFetch(const FetchPriority aFetchPriority) {
    int32_t priorityValue = nsISupportsPriority::PRIORITY_NORMAL;
    if (!StaticPrefs::network_fetchpriority_enabled()) {
      return priorityValue;
    }

    return priorityValue +
           FETCH_PRIORITY_ADJUSTMENT_FOR(link_preload_fetch, aFetchPriority);
  }
};

PreloadService::PreloadOrCoalesceResult PreloadService::PreloadOrCoalesce(
    nsIURI* aURI, const nsAString& aURL, nsContentPolicyType aPolicyType,
    const nsAString& aAs, const nsAString& aType, const nsAString& aCharset,
    const nsAString& aSrcset, const nsAString& aSizes, const nsAString& aNonce,
    const nsAString& aIntegrity, const nsAString& aCORS,
    const nsAString& aReferrerPolicy, const nsAString& aFetchPriority,
    bool aFromHeader, uint64_t aEarlyHintPreloaderId) {
  if (!aURI) {
    MOZ_ASSERT_UNREACHABLE("Should not pass null nsIURI");
    return {nullptr, false};
  }

  bool isImgSet = false;
  PreloadHashKey preloadKey;
  nsCOMPtr<nsIURI> uri = aURI;

  if (aAs.LowerCaseEqualsASCII("script")) {
    preloadKey = PreloadHashKey::CreateAsScript(uri, aCORS, aType);
  } else if (aAs.LowerCaseEqualsASCII("style")) {
    preloadKey = PreloadHashKey::CreateAsStyle(
        uri, mDocument->NodePrincipal(), dom::Element::StringToCORSMode(aCORS),
        css::eAuthorSheetFeatures /* see Loader::LoadSheet */);
  } else if (aAs.LowerCaseEqualsASCII("image")) {
    uri = mDocument->ResolvePreloadImage(BaseURIForPreload(), aURL, aSrcset,
                                         aSizes, &isImgSet);
    if (!uri) {
      return {nullptr, false};
    }

    preloadKey = PreloadHashKey::CreateAsImage(
        uri, mDocument->NodePrincipal(), dom::Element::StringToCORSMode(aCORS));
  } else if (aAs.LowerCaseEqualsASCII("font")) {
    preloadKey = PreloadHashKey::CreateAsFont(
        uri, dom::Element::StringToCORSMode(aCORS));
  } else if (aAs.LowerCaseEqualsASCII("fetch")) {
    preloadKey = PreloadHashKey::CreateAsFetch(
        uri, dom::Element::StringToCORSMode(aCORS));
  } else {
    return {nullptr, false};
  }

  if (RefPtr<PreloaderBase> preload = LookupPreload(preloadKey)) {
    return {std::move(preload), false};
  }

  if (aAs.LowerCaseEqualsASCII("script")) {
    PreloadScript(uri, aType, aCharset, aCORS, aReferrerPolicy, aNonce,
                  aFetchPriority, aIntegrity, true /* isInHead - TODO */,
                  aEarlyHintPreloaderId);
  } else if (aAs.LowerCaseEqualsASCII("style")) {
    const auto preloadKind = [&] {
      if (aEarlyHintPreloaderId) {
        MOZ_ASSERT(aFromHeader);
        return css::StylePreloadKind::FromEarlyHintsHeader;
      }
      return aFromHeader ? css::StylePreloadKind::FromLinkRelPreloadHeader
                         : css::StylePreloadKind::FromLinkRelPreloadElement;
    }();
    auto status = mDocument->PreloadStyle(
        aURI, Encoding::ForLabel(aCharset), aCORS,
        PreloadReferrerPolicy(aReferrerPolicy), aNonce, aIntegrity, preloadKind,
        aEarlyHintPreloaderId, aFetchPriority);
    switch (status) {
      case dom::SheetPreloadStatus::AlreadyComplete:
        return {nullptr, /* already_complete = */ true};
      case dom::SheetPreloadStatus::Errored:
      case dom::SheetPreloadStatus::InProgress:
        break;
    }
  } else if (aAs.LowerCaseEqualsASCII("image")) {
    PreloadImage(uri, aCORS, aReferrerPolicy, isImgSet, aEarlyHintPreloaderId,
                 aFetchPriority);
  } else if (aAs.LowerCaseEqualsASCII("font")) {
    PreloadFont(uri, aCORS, aReferrerPolicy, aEarlyHintPreloaderId,
                aFetchPriority);
  } else if (aAs.LowerCaseEqualsASCII("fetch")) {
    PreloadFetch(uri, aCORS, aReferrerPolicy, aEarlyHintPreloaderId,
                 aFetchPriority);
  }

  RefPtr<PreloaderBase> preload = LookupPreload(preloadKey);
  if (preload && aEarlyHintPreloaderId) {
    preload->SetForEarlyHints();
  }

  return {preload, false};
}

void PreloadService::PreloadScript(
    nsIURI* aURI, const nsAString& aType, const nsAString& aCharset,
    const nsAString& aCrossOrigin, const nsAString& aReferrerPolicy,
    const nsAString& aNonce, const nsAString& aFetchPriority,
    const nsAString& aIntegrity, bool aScriptFromHead,
    uint64_t aEarlyHintPreloaderId) {
  mDocument->ScriptLoader()->PreloadURI(
      aURI, aCharset, aType, aCrossOrigin, aNonce, aFetchPriority, aIntegrity,
      aScriptFromHead, falsefalsetrue,
      PreloadReferrerPolicy(aReferrerPolicy), aEarlyHintPreloaderId);
}

void PreloadService::PreloadImage(nsIURI* aURI, const nsAString& aCrossOrigin,
                                  const nsAString& aImageReferrerPolicy,
                                  bool aIsImgSet,
                                  uint64_t aEarlyHintPreloaderId,
                                  const nsAString& aFetchPriority) {
  mDocument->PreLoadImage(
      aURI, aCrossOrigin, PreloadReferrerPolicy(aImageReferrerPolicy),
      aIsImgSet, true, aEarlyHintPreloaderId, aFetchPriority);
}

void PreloadService::PreloadFont(nsIURI* aURI, const nsAString& aCrossOrigin,
                                 const nsAString& aReferrerPolicy,
                                 uint64_t aEarlyHintPreloaderId,
                                 const nsAString& aFetchPriority) {
  CORSMode cors = dom::Element::StringToCORSMode(aCrossOrigin);
  auto key = PreloadHashKey::CreateAsFont(aURI, cors);

  if (PreloadExists(key)) {
    return;
  }

  const auto fetchPriority =
      nsGenericHTMLElement::ToFetchPriority(aFetchPriority);
  const auto supportsPriorityValue =
      SupportsPriorityValueFor::LinkRelPreloadFont(fetchPriority);
  LogPriorityMapping(sPreloadServiceLog, fetchPriority, supportsPriorityValue);

  RefPtr<FontPreloader> preloader = new FontPreloader();
  dom::ReferrerPolicy referrerPolicy = PreloadReferrerPolicy(aReferrerPolicy);
  preloader->OpenChannel(key, aURI, cors, referrerPolicy, mDocument,
                         aEarlyHintPreloaderId, supportsPriorityValue);
}

void PreloadService::PreloadFetch(nsIURI* aURI, const nsAString& aCrossOrigin,
                                  const nsAString& aReferrerPolicy,
                                  uint64_t aEarlyHintPreloaderId,
                                  const nsAString& aFetchPriority) {
  CORSMode cors = dom::Element::StringToCORSMode(aCrossOrigin);
  auto key = PreloadHashKey::CreateAsFetch(aURI, cors);

  if (PreloadExists(key)) {
    return;
  }

  RefPtr<FetchPreloader> preloader = new FetchPreloader();
  dom::ReferrerPolicy referrerPolicy = PreloadReferrerPolicy(aReferrerPolicy);

  const auto fetchPriority =
      nsGenericHTMLElement::ToFetchPriority(aFetchPriority);
  const int32_t supportsPriorityValue =
      SupportsPriorityValueFor::LinkRelPreloadFetch(fetchPriority);
  if (supportsPriorityValue) {
    LogPriorityMapping(sPreloadServiceLog, fetchPriority,
                       supportsPriorityValue);
  }

  preloader->OpenChannel(key, aURI, cors, referrerPolicy, mDocument,
                         aEarlyHintPreloaderId, supportsPriorityValue);
}

// static
void PreloadService::NotifyNodeEvent(nsINode* aNode, bool aSuccess) {
  if (!aNode->IsInComposedDoc()) {
    return;
  }

  // We don't dispatch synchronously since |node| might be in a DocGroup
  // that we're not allowed to touch. (Our network request happens in the
  // DocGroup of one of the mSources nodes--not necessarily this one).

  RefPtr<AsyncEventDispatcher> dispatcher = new AsyncEventDispatcher(
      aNode, aSuccess ? u"load"_ns : u"error"_ns, CanBubble::eNo);

  dispatcher->RequireNodeInDocument();
  dispatcher->PostDOMEvent();
}

dom::ReferrerPolicy PreloadService::PreloadReferrerPolicy(
    const nsAString& aReferrerPolicy) {
  dom::ReferrerPolicy referrerPolicy =
      dom::ReferrerInfo::ReferrerPolicyAttributeFromString(aReferrerPolicy);
  if (referrerPolicy == dom::ReferrerPolicy::_empty) {
    referrerPolicy = mDocument->GetPreloadReferrerInfo()->ReferrerPolicy();
  }

  return referrerPolicy;
}

nsIURI* PreloadService::BaseURIForPreload() {
  nsIURI* documentURI = mDocument->GetDocumentURI();
  nsIURI* documentBaseURI = mDocument->GetDocBaseURI();
  return (documentURI == documentBaseURI)
             ? (mSpeculationBaseURI ? mSpeculationBaseURI.get() : documentURI)
             : documentBaseURI;
}

}  // namespace mozilla

100%


¤ Dauer der Verarbeitung: 0.13 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung ist noch experimentell.