tor-browser

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

ScriptLoadRequest.cpp (7917B)


      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 "ScriptLoadRequest.h"
      8 #include "GeckoProfiler.h"
      9 
     10 #include "mozilla/dom/Document.h"
     11 #include "mozilla/dom/ScriptLoadContext.h"
     12 #include "mozilla/dom/WorkerLoadContext.h"
     13 #include "mozilla/dom/ScriptSettings.h"
     14 #include "mozilla/StaticPrefs_dom.h"
     15 #include "mozilla/Utf8.h"  // mozilla::Utf8Unit
     16 
     17 #include "js/SourceText.h"
     18 
     19 #include "ModuleLoadRequest.h"
     20 #include "nsContentUtils.h"
     21 #include "nsIClassOfService.h"
     22 #include "nsISupportsPriority.h"
     23 
     24 using JS::SourceText;
     25 
     26 namespace JS::loader {
     27 
     28 //////////////////////////////////////////////////////////////
     29 // ScriptFetchOptions
     30 //////////////////////////////////////////////////////////////
     31 
     32 NS_IMPL_CYCLE_COLLECTION(ScriptFetchOptions, mTriggeringPrincipal)
     33 
     34 ScriptFetchOptions::ScriptFetchOptions(
     35    mozilla::CORSMode aCORSMode, const nsAString& aNonce,
     36    mozilla::dom::RequestPriority aFetchPriority,
     37    const ParserMetadata aParserMetadata, nsIPrincipal* aTriggeringPrincipal)
     38    : mCORSMode(aCORSMode),
     39      mFetchPriority(aFetchPriority),
     40      mParserMetadata(aParserMetadata),
     41      mTriggeringPrincipal(aTriggeringPrincipal),
     42      mNonce(aNonce) {}
     43 
     44 void ScriptFetchOptions::SetTriggeringPrincipal(
     45    nsIPrincipal* aTriggeringPrincipal) {
     46  MOZ_ASSERT(!mTriggeringPrincipal);
     47  mTriggeringPrincipal = aTriggeringPrincipal;
     48 }
     49 
     50 // static
     51 already_AddRefed<ScriptFetchOptions> ScriptFetchOptions::CreateDefault() {
     52  RefPtr<ScriptFetchOptions> options = new ScriptFetchOptions(
     53      mozilla::CORS_NONE, /* aNonce = */ u""_ns,
     54      mozilla::dom::RequestPriority::Auto, ParserMetadata::NotParserInserted);
     55  return options.forget();
     56 }
     57 
     58 ScriptFetchOptions::~ScriptFetchOptions() = default;
     59 
     60 //////////////////////////////////////////////////////////////
     61 // ScriptLoadRequest
     62 //////////////////////////////////////////////////////////////
     63 
     64 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ScriptLoadRequest)
     65  NS_INTERFACE_MAP_ENTRY(nsISupports)
     66 NS_INTERFACE_MAP_END
     67 
     68 NS_IMPL_CYCLE_COLLECTING_ADDREF(ScriptLoadRequest)
     69 NS_IMPL_CYCLE_COLLECTING_RELEASE(ScriptLoadRequest)
     70 
     71 // ScriptLoadRequest can be accessed from multiple threads.
     72 //
     73 // For instance, worker script loader passes the ScriptLoadRequest to
     74 // the main thread to perform the actual load.
     75 // Even while it's handled by the main thread, the ScriptLoadRequest is
     76 // the target of the worker thread's cycle collector.
     77 //
     78 // Fields that can be modified by the main thread shouldn't be touched by
     79 // the cycle collection.
     80 //
     81 // NOTE: nsIURI and nsIPrincipal doesn't have to be touched here because
     82 //       they cannot be a part of cycle.
     83 NS_IMPL_CYCLE_COLLECTION(ScriptLoadRequest, mLoadedScript, mLoadContext)
     84 
     85 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ScriptLoadRequest)
     86 NS_IMPL_CYCLE_COLLECTION_TRACE_END
     87 
     88 ScriptLoadRequest::ScriptLoadRequest(ScriptKind aKind,
     89                                     const SRIMetadata& aIntegrity,
     90                                     nsIURI* aReferrer,
     91                                     LoadContextBase* aContext)
     92    : mKind(aKind),
     93      mState(State::CheckingCache),
     94      mFetchSourceOnly(false),
     95      mHasSourceMapURL_(false),
     96      mHasDirtyCache_(false),
     97      mHadPostponed_(false),
     98      mDiskCachingPlan(CachingPlan::Uninitialized),
     99      mMemoryCachingPlan(CachingPlan::Uninitialized),
    100      mIntegrity(aIntegrity),
    101      mReferrer(aReferrer),
    102      mLoadContext(aContext),
    103      mEarlyHintPreloaderId(0) {
    104  if (mLoadContext) {
    105    mLoadContext->SetRequest(this);
    106  }
    107 }
    108 
    109 ScriptLoadRequest::~ScriptLoadRequest() {}
    110 
    111 void ScriptLoadRequest::SetReady() {
    112  MOZ_ASSERT(!IsFinished());
    113  mState = State::Ready;
    114 }
    115 
    116 void ScriptLoadRequest::Cancel() {
    117  mState = State::Canceled;
    118  if (HasScriptLoadContext()) {
    119    GetScriptLoadContext()->MaybeCancelOffThreadScript();
    120  }
    121 }
    122 
    123 bool ScriptLoadRequest::HasScriptLoadContext() const {
    124  return HasLoadContext() && mLoadContext->IsWindowContext();
    125 }
    126 
    127 bool ScriptLoadRequest::HasWorkerLoadContext() const {
    128  return HasLoadContext() && mLoadContext->IsWorkerContext();
    129 }
    130 
    131 mozilla::dom::ScriptLoadContext* ScriptLoadRequest::GetScriptLoadContext() {
    132  MOZ_ASSERT(mLoadContext);
    133  return mLoadContext->AsWindowContext();
    134 }
    135 
    136 const mozilla::dom::ScriptLoadContext* ScriptLoadRequest::GetScriptLoadContext()
    137    const {
    138  MOZ_ASSERT(mLoadContext);
    139  return mLoadContext->AsWindowContext();
    140 }
    141 
    142 mozilla::loader::SyncLoadContext* ScriptLoadRequest::GetSyncLoadContext() {
    143  MOZ_ASSERT(mLoadContext);
    144  return mLoadContext->AsSyncContext();
    145 }
    146 
    147 mozilla::dom::WorkerLoadContext* ScriptLoadRequest::GetWorkerLoadContext() {
    148  MOZ_ASSERT(mLoadContext);
    149  return mLoadContext->AsWorkerContext();
    150 }
    151 
    152 mozilla::dom::WorkletLoadContext* ScriptLoadRequest::GetWorkletLoadContext() {
    153  MOZ_ASSERT(mLoadContext);
    154  return mLoadContext->AsWorkletContext();
    155 }
    156 
    157 ModuleLoadRequest* ScriptLoadRequest::AsModuleRequest() {
    158  MOZ_ASSERT(IsModuleRequest());
    159  return static_cast<ModuleLoadRequest*>(this);
    160 }
    161 
    162 const ModuleLoadRequest* ScriptLoadRequest::AsModuleRequest() const {
    163  MOZ_ASSERT(IsModuleRequest());
    164  return static_cast<const ModuleLoadRequest*>(this);
    165 }
    166 
    167 void ScriptLoadRequest::CacheEntryFound(LoadedScript* aLoadedScript) {
    168  MOZ_ASSERT(IsCheckingCache());
    169 
    170  SetCacheEntry(aLoadedScript);
    171 }
    172 
    173 void ScriptLoadRequest::CacheEntryRevived(LoadedScript* aLoadedScript) {
    174  MOZ_ASSERT(IsFetching());
    175 
    176  SetCacheEntry(aLoadedScript);
    177 
    178  // NOTE: The caller should keep using the "fetching" path, with the
    179  //       cached stencil, and skip the compilation.
    180  mState = State::Fetching;
    181 }
    182 
    183 void ScriptLoadRequest::SetCacheEntry(LoadedScript* aLoadedScript) {
    184  switch (mKind) {
    185    case ScriptKind::eClassic:
    186      MOZ_ASSERT(aLoadedScript->IsClassicScript());
    187 
    188      mLoadedScript = aLoadedScript;
    189 
    190      // Classic scripts can be set ready once the script itself is ready.
    191      mState = State::Ready;
    192      break;
    193    case ScriptKind::eImportMap:
    194      MOZ_ASSERT(aLoadedScript->IsImportMapScript());
    195 
    196      mLoadedScript = aLoadedScript;
    197 
    198      mState = State::Ready;
    199      break;
    200    case ScriptKind::eModule:
    201      // NOTE: The cache entry has "module" kind, but it's not ModuleScript
    202      //       instance, given ModuleScript has GC pointers.
    203      MOZ_ASSERT(aLoadedScript->IsModuleScript());
    204 
    205      mLoadedScript = ModuleScript::FromCache(*aLoadedScript);
    206 
    207      // Modules need to wait for fetching dependencies before setting to
    208      // Ready.
    209      mState = State::Fetching;
    210      break;
    211    case ScriptKind::eEvent:
    212      MOZ_ASSERT_UNREACHABLE("EventScripts are not using ScriptLoadRequest");
    213      break;
    214  }
    215 }
    216 
    217 void ScriptLoadRequest::NoCacheEntryFound(
    218    mozilla::dom::ReferrerPolicy aReferrerPolicy,
    219    ScriptFetchOptions* aFetchOptions, nsIURI* aURI) {
    220  MOZ_ASSERT(IsCheckingCache());
    221  // At the time where we check in the cache, the BaseURL() is not set, as this
    222  // is resolved by the network. Thus we use the aURI passed by the consumer,
    223  // which is the original URI used for the request, for checking the cache
    224  // and later replace the BaseURL() using what the Channel->GetURI will
    225  // provide.
    226  switch (mKind) {
    227    case ScriptKind::eClassic:
    228      mLoadedScript = new ClassicScript(aReferrerPolicy, aFetchOptions, aURI);
    229      break;
    230    case ScriptKind::eImportMap:
    231      mLoadedScript = new ImportMapScript(aReferrerPolicy, aFetchOptions, aURI);
    232      break;
    233    case ScriptKind::eModule:
    234      mLoadedScript = new ModuleScript(aReferrerPolicy, aFetchOptions, aURI);
    235      break;
    236    case ScriptKind::eEvent:
    237      MOZ_ASSERT_UNREACHABLE("EventScripts are not using ScriptLoadRequest");
    238      break;
    239  }
    240  mState = State::Fetching;
    241 }
    242 
    243 }  // namespace JS::loader