tor-browser

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

ScriptLoadRequest.h (11983B)


      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 #ifndef js_loader_ScriptLoadRequest_h
      8 #define js_loader_ScriptLoadRequest_h
      9 
     10 #include "js/experimental/JSStencil.h"
     11 #include "js/RootingAPI.h"
     12 #include "js/SourceText.h"
     13 #include "js/TypeDecls.h"
     14 #include "mozilla/Assertions.h"
     15 #include "mozilla/dom/CacheExpirationTime.h"
     16 #include "mozilla/dom/SRIMetadata.h"
     17 #include "mozilla/LinkedList.h"
     18 #include "mozilla/PreloaderBase.h"
     19 #include "mozilla/RefPtr.h"
     20 #include "mozilla/SharedSubResourceCache.h"  // mozilla::SubResourceNetworkMetadataHolder
     21 #include "mozilla/StaticPrefs_dom.h"
     22 #include "nsCycleCollectionParticipant.h"
     23 #include "nsIGlobalObject.h"
     24 #include "LoadedScript.h"
     25 #include "ScriptKind.h"
     26 #include "ScriptFetchOptions.h"
     27 
     28 namespace mozilla::dom {
     29 
     30 class ScriptLoadContext;
     31 class WorkerLoadContext;
     32 class WorkletLoadContext;
     33 enum class RequestPriority : uint8_t;
     34 
     35 }  // namespace mozilla::dom
     36 
     37 namespace mozilla::loader {
     38 class SyncLoadContext;
     39 }  // namespace mozilla::loader
     40 
     41 namespace JS::loader {
     42 
     43 class LoadContextBase;
     44 class ModuleLoadRequest;
     45 class ScriptLoadRequestList;
     46 
     47 /*
     48 * ScriptLoadRequest
     49 *
     50 * ScriptLoadRequest is a generic representation of a request/response for
     51 * JavaScript file that will be loaded by a Script/Module loader. This
     52 * representation is used by the following:
     53 *   - DOM ScriptLoader / ModuleLoader
     54 *   - worker ScriptLoader / ModuleLoader
     55 *   - worklet ScriptLoader
     56 *   - SyncModuleLoader
     57 *
     58 * The ScriptLoadRequest contains information specific to the current request,
     59 * such as the kind of script (classic, module, etc), and the reference to the
     60 * LoadedScript which contains the information independent of the current
     61 * request, such as the URI, the ScriptFetchOptions, etc.
     62 *
     63 * Relationship to ScriptLoadContext:
     64 *
     65 * ScriptLoadRequest and ScriptLoadContexts have a circular pointer.  A
     66 * ScriptLoadContext augments the loading of a ScriptLoadRequest by providing
     67 * additional information regarding the loading and evaluation behavior (see
     68 * the ScriptLoadContext class for details).  In terms of responsibility,
     69 * the ScriptLoadRequest represents "What" is being loaded, and the
     70 * ScriptLoadContext represents "How".
     71 *
     72 * TODO: see if we can use it in the jsshell script loader. We need to either
     73 * remove ISUPPORTS or find a way to encorporate that in the jsshell. We would
     74 * then only have one implementation of the script loader, and it would be
     75 * tested whenever jsshell tests are run. This would mean finding another way to
     76 * create ScriptLoadRequest lists.
     77 *
     78 */
     79 
     80 class ScriptLoadRequest : public nsISupports,
     81                          private mozilla::LinkedListElement<ScriptLoadRequest>,
     82                          public LoadedScriptDelegate<ScriptLoadRequest> {
     83  using super = LinkedListElement<ScriptLoadRequest>;
     84 
     85  // Allow LinkedListElement<ScriptLoadRequest> to cast us to itself as needed.
     86  friend class mozilla::LinkedListElement<ScriptLoadRequest>;
     87  friend class ScriptLoadRequestList;
     88 
     89 protected:
     90  virtual ~ScriptLoadRequest();
     91 
     92 public:
     93  using SRIMetadata = mozilla::dom::SRIMetadata;
     94  ScriptLoadRequest(ScriptKind aKind, const SRIMetadata& aIntegrity,
     95                    nsIURI* aReferrer, LoadContextBase* aContext);
     96 
     97  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
     98  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ScriptLoadRequest)
     99 
    100  using super::getNext;
    101  using super::isInList;
    102 
    103  template <typename T, typename D = DeletePolicy<T>>
    104  using UniquePtr = mozilla::UniquePtr<T, D>;
    105 
    106  bool IsModuleRequest() const { return mKind == ScriptKind::eModule; }
    107  bool IsImportMapRequest() const { return mKind == ScriptKind::eImportMap; }
    108 
    109  ModuleLoadRequest* AsModuleRequest();
    110  const ModuleLoadRequest* AsModuleRequest() const;
    111 
    112  CacheExpirationTime ExpirationTime() const {
    113    // The request's expiration time is used only when it's received from
    114    // necko.  For in-memory cached, case, the
    115    // SharedSubResourceCache::CompleteSubResource::mExpirationTime field is
    116    // used instead.
    117    MOZ_ASSERT(!IsCachedStencil());
    118    return mExpirationTime;
    119  }
    120 
    121  void SetMinimumExpirationTime(const CacheExpirationTime& aExpirationTime) {
    122    mExpirationTime.SetMinimum(aExpirationTime);
    123  }
    124 
    125  virtual bool IsTopLevel() const { return true; };
    126 
    127  virtual void Cancel();
    128 
    129  virtual void SetReady();
    130 
    131  enum class State : uint8_t {
    132    CheckingCache,
    133    Fetching,
    134    Compiling,
    135    Ready,
    136    Canceled
    137  };
    138 
    139  // Before any attempt at fetching resources from the cache we should first
    140  // make sure that the resource does not yet exists in the cache. In which case
    141  // we might simply alias its LoadedScript. Otherwise a new one would be
    142  // created.
    143  bool IsCheckingCache() const { return mState == State::CheckingCache; }
    144 
    145  // Setup and load resources, to fill the LoadedScript and make it usable by
    146  // the JavaScript engine.
    147  bool IsFetching() const { return mState == State::Fetching; }
    148  bool IsCompiling() const { return mState == State::Compiling; }
    149  bool IsCanceled() const { return mState == State::Canceled; }
    150 
    151  // Return whether the request has been completed, either successfully or
    152  // otherwise.
    153  bool IsFinished() const {
    154    return mState == State::Ready || mState == State::Canceled;
    155  }
    156 
    157  mozilla::dom::RequestPriority FetchPriority() const {
    158    return FetchOptions()->mFetchPriority;
    159  }
    160 
    161  enum ParserMetadata ParserMetadata() const {
    162    return FetchOptions()->mParserMetadata;
    163  }
    164 
    165  const nsString& Nonce() const { return FetchOptions()->mNonce; }
    166 
    167  nsIPrincipal* TriggeringPrincipal() const {
    168    return FetchOptions()->mTriggeringPrincipal;
    169  }
    170 
    171  // Convert a CheckingCache ScriptLoadRequest into a Ready one, by populating
    172  // the script data from cached script.
    173  void CacheEntryFound(LoadedScript* aLoadedScript);
    174 
    175  void CacheEntryRevived(LoadedScript* aLoadedScript);
    176 
    177  // Convert a CheckingCache ScriptLoadRequest into a Fetching one, by creating
    178  // a new LoadedScript which is matching the ScriptKind provided when
    179  // constructing this ScriptLoadRequest.
    180  void NoCacheEntryFound(mozilla::dom::ReferrerPolicy aReferrerPolicy,
    181                         ScriptFetchOptions* aFetchOptions, nsIURI* aURI);
    182 
    183 private:
    184  void SetCacheEntry(LoadedScript* aLoadedScript);
    185 
    186 public:
    187  bool PassedConditionForDiskCache() const {
    188    return mDiskCachingPlan == CachingPlan::PassedCondition;
    189  }
    190 
    191  bool PassedConditionForMemoryCache() const {
    192    return mMemoryCachingPlan == CachingPlan::PassedCondition;
    193  }
    194 
    195  bool PassedConditionForEitherCache() const {
    196    return PassedConditionForDiskCache() || PassedConditionForMemoryCache();
    197  }
    198 
    199  void MarkNotCacheable() {
    200    mDiskCachingPlan = CachingPlan::NotCacheable;
    201    mMemoryCachingPlan = CachingPlan::NotCacheable;
    202  }
    203 
    204  bool IsMarkedNotCacheable() const {
    205    MOZ_ASSERT_IF(mDiskCachingPlan == CachingPlan::NotCacheable,
    206                  mMemoryCachingPlan == CachingPlan::NotCacheable);
    207    MOZ_ASSERT_IF(mDiskCachingPlan != CachingPlan::NotCacheable,
    208                  mMemoryCachingPlan != CachingPlan::NotCacheable);
    209    return mDiskCachingPlan == CachingPlan::NotCacheable;
    210  }
    211 
    212  void MarkSkippedDiskCaching() {
    213    MOZ_ASSERT(mDiskCachingPlan == CachingPlan::Uninitialized ||
    214               mDiskCachingPlan == CachingPlan::PassedCondition);
    215    mDiskCachingPlan = CachingPlan::Skipped;
    216  }
    217 
    218  void MarkSkippedMemoryCaching() {
    219    MOZ_ASSERT(mMemoryCachingPlan == CachingPlan::Uninitialized ||
    220               mMemoryCachingPlan == CachingPlan::PassedCondition);
    221    mMemoryCachingPlan = CachingPlan::Skipped;
    222  }
    223 
    224  void MarkSkippedAllCaching() {
    225    MarkSkippedDiskCaching();
    226    MarkSkippedMemoryCaching();
    227  }
    228 
    229  void MarkPassedConditionForDiskCache() {
    230    MOZ_ASSERT(mDiskCachingPlan == CachingPlan::Uninitialized);
    231    mDiskCachingPlan = CachingPlan::PassedCondition;
    232  }
    233 
    234  void MarkPassedConditionForMemoryCache() {
    235    MOZ_ASSERT(mMemoryCachingPlan == CachingPlan::Uninitialized);
    236    mMemoryCachingPlan = CachingPlan::PassedCondition;
    237  }
    238 
    239  mozilla::CORSMode CORSMode() const { return FetchOptions()->mCORSMode; }
    240 
    241  bool HasLoadContext() const { return mLoadContext; }
    242  bool HasScriptLoadContext() const;
    243  bool HasWorkerLoadContext() const;
    244 
    245  mozilla::dom::ScriptLoadContext* GetScriptLoadContext();
    246  const mozilla::dom::ScriptLoadContext* GetScriptLoadContext() const;
    247 
    248  mozilla::loader::SyncLoadContext* GetSyncLoadContext();
    249 
    250  mozilla::dom::WorkerLoadContext* GetWorkerLoadContext();
    251 
    252  mozilla::dom::WorkletLoadContext* GetWorkletLoadContext();
    253 
    254  const LoadedScript* getLoadedScript() const { return mLoadedScript.get(); }
    255  LoadedScript* getLoadedScript() { return mLoadedScript.get(); }
    256 
    257  bool HasSourceMapURL() const { return mHasSourceMapURL_; }
    258  const nsString& GetSourceMapURL() const {
    259    MOZ_ASSERT(mHasSourceMapURL_);
    260    return mMaybeSourceMapURL_;
    261  }
    262  void SetSourceMapURL(const nsString& aSourceMapURL) {
    263    MOZ_ASSERT(!mHasSourceMapURL_);
    264    mMaybeSourceMapURL_ = aSourceMapURL;
    265    mHasSourceMapURL_ = true;
    266  }
    267 
    268  bool HasDirtyCache() const { return mHasDirtyCache_; }
    269  void SetHasDirtyCache() { mHasDirtyCache_ = true; }
    270 
    271  bool HadPostponed() const { return mHadPostponed_; }
    272  void SetHadPostponed() { mHadPostponed_ = true; }
    273 
    274 public:
    275  // Fields.
    276 
    277  // Whether this is a classic script, a module script, or an import map.
    278  const ScriptKind mKind;
    279 
    280  // Are we still waiting for a load to complete?
    281  State mState;
    282 
    283  // Request source, not cached serialized Stencil.
    284  bool mFetchSourceOnly : 1;
    285 
    286  // Becomes true if this has source map url.
    287  //
    288  // Do not access directly.
    289  // Use HasSourceMapURL(), SetSourceMapURL(), and GetSourceMapURL().
    290  bool mHasSourceMapURL_ : 1;
    291 
    292  // Set to true if this response is found in the in-memory cache, but the
    293  // cache is marked as dirty, and needs validation.
    294  //
    295  // This request should go to necko, and when the response is received,
    296  // the cache should be either revived or evicted.
    297  bool mHasDirtyCache_ : 1;
    298 
    299  // Set to true if this script had already been postponed in the scheduling.
    300  bool mHadPostponed_ : 1;
    301 
    302  enum class CachingPlan : uint8_t {
    303    // This is not yet considered for caching.
    304    Uninitialized,
    305 
    306    // This request is not cacheable (e.g. inline script, JSON module).
    307    NotCacheable,
    308 
    309    // This request is cacheable, but is marked for skipping due to
    310    // not passing conditions.
    311    Skipped,
    312 
    313    // This fits the condition for the caching (e.g. file size, fetch count).
    314    PassedCondition,
    315  };
    316  CachingPlan mDiskCachingPlan : 2;
    317  CachingPlan mMemoryCachingPlan : 2;
    318 
    319  CacheExpirationTime mExpirationTime = CacheExpirationTime::Never();
    320 
    321  RefPtr<mozilla::SubResourceNetworkMetadataHolder> mNetworkMetadata;
    322  const SRIMetadata mIntegrity;
    323  const nsCOMPtr<nsIURI> mReferrer;
    324 
    325  // Holds source map url for loaded scripts.
    326  //
    327  // Do not access directly.
    328  // Use HasSourceMapURL(), SetSourceMapURL(), and GetSourceMapURL().
    329  nsString mMaybeSourceMapURL_;
    330 
    331  nsCOMPtr<nsIPrincipal> mOriginPrincipal;
    332 
    333  // Keep the URI's filename alive during off thread parsing.
    334  // Also used by workers to report on errors while loading, and used by
    335  // worklets as the file name in compile options.
    336  nsAutoCString mURL;
    337 
    338  // The loaded script holds the data which can be shared among similar requests
    339  RefPtr<LoadedScript> mLoadedScript;
    340 
    341  // LoadContext for augmenting the load depending on the loading
    342  // context (DOM, Worker, etc.)
    343  RefPtr<LoadContextBase> mLoadContext;
    344 
    345  // EarlyHintRegistrar id to connect the http channel back to the preload, with
    346  // a default of value of 0 indicating that this request is not an early hints
    347  // preload.
    348  uint64_t mEarlyHintPreloaderId;
    349 };
    350 
    351 }  // namespace JS::loader
    352 
    353 #endif  // js_loader_ScriptLoadRequest_h