tor-browser

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

WorkerLoadContext.h (7398B)


      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 mozilla_dom_workers_WorkerLoadContext_h__
      8 #define mozilla_dom_workers_WorkerLoadContext_h__
      9 
     10 #include "js/loader/LoadContextBase.h"
     11 #include "js/loader/ScriptKind.h"
     12 #include "js/loader/ScriptLoadRequest.h"
     13 #include "mozilla/CORSMode.h"
     14 #include "mozilla/dom/Promise.h"
     15 #include "nsIChannel.h"
     16 #include "nsIInputStream.h"
     17 #include "nsIRequest.h"
     18 
     19 class nsIReferrerInfo;
     20 class nsIURI;
     21 
     22 namespace mozilla::dom {
     23 
     24 class ClientInfo;
     25 class WorkerPrivate;
     26 
     27 namespace workerinternals::loader {
     28 class CacheCreator;
     29 class ScriptLoaderRunnable;
     30 class WorkerScriptLoader;
     31 }  // namespace workerinternals::loader
     32 
     33 /*
     34 * WorkerLoadContext (for all workers)
     35 *
     36 * LoadContexts augment the loading of a ScriptLoadRequest. They
     37 * describe how a ScriptLoadRequests loading and evaluation needs to be
     38 * augmented, based on the information provided by the loading context. The
     39 * WorkerLoadContext has the following generic fields applied to all worker
     40 * ScriptLoadRequests (and primarily used for error handling):
     41 *
     42 *    * mMutedErrorFlag
     43 *        Set when we finish loading a script, and used to determine whether a
     44 *        given error is thrown or muted.
     45 *    * mLoadResult
     46 *        In order to report errors correctly in the worker thread, we need to
     47 *        move them from the main thread to the worker. This field records the
     48 *        load error, for throwing when we return to the worker thread.
     49 *    * mKind
     50 *        See documentation of WorkerLoadContext::Kind.
     51 *    * mClientInfo
     52 *        A snapshot of a global living in the system (see documentation for
     53 *        ClientInfo). In worker loading, this field is important for CSP
     54 *        information and knowing what to intercept for Service Worker
     55 *        interception.
     56 *    * mChannel
     57 *        The channel used by this request for it's load. Used for cancellation,
     58 *        in order to cancel the stream.
     59 *
     60 * The rest of the fields on this class focus on enabling the ServiceWorker
     61 * usecase, in particular -- using the Cache API to store the worker so that
     62 * in the case of (for example) a page refresh, the service worker itself is
     63 * persisted so that it can do other work. For more details see the
     64 * CacheLoadHandler.h file.
     65 *
     66 */
     67 
     68 class WorkerLoadContext : public JS::loader::LoadContextBase {
     69 public:
     70  /* Worker Load Context Kinds
     71   *
     72   * A script that is loaded and run as a worker can be one of several species.
     73   * Each may have slightly different behavior, but they fall into roughly two
     74   * categories: the Main Worker Script (the script that triggers the first
     75   * load) and scripts that are attached to this main worker script.
     76   *
     77   * In the specification, the Main Worker Script is referred to as the "top
     78   * level script" and is defined here:
     79   * https://html.spec.whatwg.org/multipage/webappapis.html#fetching-scripts-is-top-level
     80   */
     81 
     82  enum Kind {
     83    // Indicates that the is-top-level bit is true. This may be a Classic script
     84    // or a Module script.
     85    MainScript,
     86    // We are importing a script from the worker via ImportScript. This may only
     87    // be a Classic script.
     88    ImportScript,
     89    // We are importing a script from the worker via a Static Import. This may
     90    // only
     91    // be a Module script.
     92    StaticImport,
     93    DynamicImport,
     94    // We have an attached debugger, and these should be treated specially and
     95    // not like a main script (regardless of their type). This is not part of
     96    // the specification.
     97    DebuggerScript
     98  };
     99 
    100  WorkerLoadContext(Kind aKind, const Maybe<ClientInfo>& aClientInfo,
    101                    workerinternals::loader::WorkerScriptLoader* aScriptLoader,
    102                    bool aOnlyExistingCachedResourcesAllowed);
    103 
    104  // Used to detect if the `is top-level` bit is set on a given module.
    105  bool IsTopLevel();
    106 
    107  static Kind GetKind(bool isMainScript, bool isDebuggerScript) {
    108    if (isDebuggerScript) {
    109      return Kind::DebuggerScript;
    110    }
    111    if (isMainScript) {
    112      return Kind::MainScript;
    113    }
    114    return Kind::ImportScript;
    115  };
    116 
    117  /* These fields are used by all workers */
    118  Maybe<bool> mMutedErrorFlag;
    119  nsresult mLoadResult = NS_ERROR_NOT_INITIALIZED;
    120  bool mLoadingFinished = false;
    121  bool mIsTopLevel = true;
    122  Kind mKind;
    123  Maybe<ClientInfo> mClientInfo;
    124  nsCOMPtr<nsIChannel> mChannel;
    125  RefPtr<workerinternals::loader::WorkerScriptLoader> mScriptLoader;
    126 
    127  /* These fields are only used by service workers */
    128  /* TODO: Split out a ServiceWorkerLoadContext */
    129  // This full URL string is populated only if this object is used in a
    130  // ServiceWorker.
    131  nsCString mFullURL;
    132 
    133  // This promise is set only when the script is for a ServiceWorker but
    134  // it's not in the cache yet. The promise is resolved when the full body is
    135  // stored into the cache.  mCachePromise will be set to nullptr after
    136  // resolution.
    137  RefPtr<Promise> mCachePromise;
    138 
    139  // The reader stream the cache entry should be filled from, for those cases
    140  // when we're going to have an mCachePromise.
    141  nsCOMPtr<nsIInputStream> mCacheReadStream;
    142 
    143  enum CacheStatus {
    144    // By default a normal script is just loaded from the network. But for
    145    // ServiceWorkers, we have to check if the cache contains the script and
    146    // load it from the cache.
    147    Uncached,
    148 
    149    WritingToCache,
    150 
    151    ReadingFromCache,
    152 
    153    // This script has been loaded from the ServiceWorker cache.
    154    Cached,
    155 
    156    // This script must be stored in the ServiceWorker cache.
    157    ToBeCached,
    158 
    159    // Something went wrong or the worker went away.
    160    Cancel
    161  };
    162 
    163  CacheStatus mCacheStatus = Uncached;
    164 
    165  // If the requested script is not currently in the cache, should we initiate
    166  // a request to fetch and cache it?  Only ServiceWorkers that are being
    167  // installed are allowed to go to the network (and then cache the result).
    168  bool mOnlyExistingCachedResourcesAllowed = false;
    169 
    170  bool IsAwaitingPromise() const { return bool(mCachePromise); }
    171 };
    172 
    173 class ThreadSafeRequestHandle final {
    174 public:
    175  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(ThreadSafeRequestHandle)
    176 
    177  ThreadSafeRequestHandle(JS::loader::ScriptLoadRequest* aRequest,
    178                          nsISerialEventTarget* aSyncTarget);
    179 
    180  JS::loader::ScriptLoadRequest* GetRequest() const { return mRequest; }
    181 
    182  WorkerLoadContext* GetContext();
    183 
    184  bool IsEmpty() { return !mRequest; }
    185 
    186  // Runnable controls
    187  nsresult OnStreamComplete(nsresult aStatus);
    188 
    189  void LoadingFinished(nsresult aRv);
    190 
    191  void MaybeExecuteFinishedScripts();
    192 
    193  bool IsCancelled();
    194 
    195  bool Finished() {
    196    return GetContext()->mLoadingFinished && !GetContext()->IsAwaitingPromise();
    197  }
    198 
    199  nsresult GetCancelResult();
    200 
    201  already_AddRefed<JS::loader::ScriptLoadRequest> ReleaseRequest();
    202 
    203  workerinternals::loader::CacheCreator* GetCacheCreator();
    204 
    205  RefPtr<workerinternals::loader::ScriptLoaderRunnable> mRunnable;
    206 
    207  bool mExecutionScheduled = false;
    208 
    209 private:
    210  ~ThreadSafeRequestHandle();
    211 
    212  RefPtr<JS::loader::ScriptLoadRequest> mRequest;
    213  nsCOMPtr<nsISerialEventTarget> mOwningEventTarget;
    214 };
    215 
    216 }  // namespace mozilla::dom
    217 #endif /* mozilla_dom_workers_WorkerLoadContext_h__ */