tor-browser

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

ScriptLoader.h (13920B)


      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_scriptloader_h__
      8 #define mozilla_dom_workers_scriptloader_h__
      9 
     10 #include "js/loader/ModuleLoaderBase.h"
     11 #include "js/loader/ScriptLoadRequest.h"
     12 #include "js/loader/ScriptLoadRequestList.h"
     13 #include "mozilla/Maybe.h"
     14 #include "mozilla/dom/WorkerBinding.h"
     15 #include "mozilla/dom/WorkerCommon.h"
     16 #include "mozilla/dom/WorkerLoadContext.h"
     17 #include "mozilla/dom/WorkerRef.h"
     18 #include "mozilla/dom/workerinternals/WorkerModuleLoader.h"
     19 #include "nsIContentPolicy.h"
     20 #include "nsStringFwd.h"
     21 #include "nsTArrayForwardDeclare.h"
     22 
     23 class nsIChannel;
     24 class nsICookieJarSettings;
     25 class nsILoadGroup;
     26 class nsIPrincipal;
     27 class nsIReferrerInfo;
     28 class nsIURI;
     29 
     30 namespace mozilla {
     31 
     32 class ErrorResult;
     33 
     34 namespace dom {
     35 
     36 class ClientInfo;
     37 class Document;
     38 struct WorkerLoadInfo;
     39 class WorkerPrivate;
     40 class SerializedStackHolder;
     41 
     42 enum WorkerScriptType { WorkerScript, DebuggerScript };
     43 
     44 namespace workerinternals {
     45 
     46 namespace loader {
     47 class ScriptExecutorRunnable;
     48 class ScriptLoaderRunnable;
     49 class CachePromiseHandler;
     50 class CacheLoadHandler;
     51 class CacheCreator;
     52 class NetworkLoadHandler;
     53 
     54 /*
     55 * [DOMDOC] WorkerScriptLoader
     56 *
     57 * The WorkerScriptLoader is the primary class responsible for loading all
     58 * Workers, including: ServiceWorkers, SharedWorkers, RemoteWorkers, and
     59 * dedicated Workers. Our implementation also includes a subtype of dedicated
     60 * workers: ChromeWorker, which exposes information that isn't normally
     61 * accessible on a dedicated worker. See [1] for more information.
     62 *
     63 * Due to constraints around fetching, this class currently delegates the
     64 * "Fetch" portion of its work load to the main thread. Unlike the DOM
     65 * ScriptLoader, the WorkerScriptLoader is not persistent and is not reused for
     66 * subsequent loads. That means for each iteration of loading (for example,
     67 * loading the main script, followed by a load triggered by ImportScripts), we
     68 * recreate this class, and handle the case independently.
     69 *
     70 * The flow of requests across the boundaries looks like this:
     71 *
     72 *    +----------------------------+
     73 *    | new WorkerScriptLoader(..) |
     74 *    +----------------------------+
     75 *                   |
     76 *                   V
     77 *            +-------------------------------------------+
     78 *            | WorkerScriptLoader::DispatchLoadScripts() |
     79 *            +-------------------------------------------+
     80 *                   |
     81 *                   V
     82 *            +............................+
     83 *            | new ScriptLoaderRunnable() |
     84 *            +............................+
     85 *                   :
     86 *                   V
     87 *  #####################################################################
     88 *                             Enter Main thread
     89 *  #####################################################################
     90 *                   :
     91 *                   V
     92 *  +.............................+     For each: Is a normal Worker?
     93 *  | ScriptLoaderRunnable::Run() |----------------------------------+
     94 *  +.............................+                                  |
     95 *                   |                                               V
     96 *                   |               +----------------------------------+
     97 *                   |               | WorkerScriptLoader::LoadScript() |
     98 *                   |               +----------------------------------+
     99 *                   |                                               |
    100 *                   | For each request: Is a ServiceWorker?         |
    101 *                   |                                               |
    102 *                   V                                               V
    103 *   +==================+   No script in cache?   +====================+
    104 *   | CacheLoadHandler |------------------------>| NetworkLoadHandler |
    105 *   +==================+                         +====================+
    106 *      :                                                    :
    107 *      : Loaded from Cache                                  : Loaded by Network
    108 *      :   +..........................................+     :
    109 *      +---| ScriptLoaderRunnable::OnStreamComplete() |<----+
    110 *          +..........................................+
    111 *                             |
    112 *                             | A request is ready, is it in post order?
    113 *                             |
    114 *                             | call DispatchPendingProcessRequests()
    115 *                             | This creates ScriptExecutorRunnable
    116 *            +..............................+
    117 *            | new ScriptLoaderExecutable() |
    118 *            +..............................+
    119 *                             :
    120 *                             V
    121 *  #####################################################################
    122 *                           Enter worker thread
    123 *  #####################################################################
    124 *                             :
    125 *                             V
    126 *          +...............................+         All Scripts Executed?
    127 *          | ScriptLoaderExecutable::Run() | -------------+
    128 *          +...............................+              :
    129 *                                                         :
    130 *                                                         : yes. Do execution
    131 *                                                         : then shutdown.
    132 *                                                         :
    133 *                                                         V
    134 *                       +--------------------------------------------+
    135 *                       | WorkerScriptLoader::ShutdownScriptLoader() |
    136 *                       +--------------------------------------------+
    137 */
    138 
    139 class WorkerScriptLoader : public JS::loader::ScriptLoaderInterface,
    140                           public nsINamed {
    141  friend class ScriptExecutorRunnable;
    142  friend class ScriptLoaderRunnable;
    143  friend class CachePromiseHandler;
    144  friend class CacheLoadHandler;
    145  friend class CacheCreator;
    146  friend class NetworkLoadHandler;
    147  friend class WorkerModuleLoader;
    148 
    149  RefPtr<ThreadSafeWorkerRef> mWorkerRef;
    150  UniquePtr<SerializedStackHolder> mOriginStack;
    151  nsString mOriginStackJSON;
    152  nsCOMPtr<nsISerialEventTarget> mSyncLoopTarget;
    153  ScriptLoadRequestList mLoadingRequests;
    154  ScriptLoadRequestList mLoadedRequests;
    155  Maybe<ServiceWorkerDescriptor> mController;
    156  WorkerScriptType mWorkerScriptType;
    157  ErrorResult& mRv;
    158  bool mExecutionAborted = false;
    159  bool mMutedErrorFlag = false;
    160 
    161  // Count of loading module requests. mLoadingRequests doesn't keep track of
    162  // child module requests.
    163  // This member should be accessed on worker thread.
    164  uint32_t mLoadingModuleRequestCount;
    165 
    166  // Worker cancellation related Mutex
    167  //
    168  // Modified on the worker thread.
    169  // It is ok to *read* this without a lock on the worker.
    170  // Main thread must always acquire a lock.
    171  bool mCleanedUp MOZ_GUARDED_BY(
    172      mCleanUpLock);  // To specify if the cleanUp() has been done.
    173 
    174  Mutex& CleanUpLock() MOZ_RETURN_CAPABILITY(mCleanUpLock) {
    175    return mCleanUpLock;
    176  }
    177 
    178  bool CleanedUp() const MOZ_REQUIRES(mCleanUpLock) {
    179    mCleanUpLock.AssertCurrentThreadOwns();
    180    return mCleanedUp;
    181  }
    182 
    183  // Ensure the worker and the main thread won't race to access |mCleanedUp|.
    184  // This should perhaps be a EventTargetAndLockCapability to model the
    185  // reader/writer behaviour on mCleanedUp better.
    186  Mutex mCleanUpLock;
    187 
    188 public:
    189  NS_DECL_THREADSAFE_ISUPPORTS
    190 
    191  static already_AddRefed<WorkerScriptLoader> Create(
    192      WorkerPrivate* aWorkerPrivate,
    193      UniquePtr<SerializedStackHolder> aOriginStack,
    194      nsISerialEventTarget* aSyncLoopTarget, WorkerScriptType aWorkerScriptType,
    195      ErrorResult& aRv);
    196 
    197  bool CreateScriptRequests(const nsTArray<nsString>& aScriptURLs,
    198                            const mozilla::Encoding* aDocumentEncoding,
    199                            bool aIsMainScript);
    200 
    201  ScriptLoadRequest* GetMainScript();
    202 
    203  already_AddRefed<ScriptLoadRequest> CreateScriptLoadRequest(
    204      const nsString& aScriptURL, const mozilla::Encoding* aDocumentEncoding,
    205      bool aIsMainScript, nsresult* aRv);
    206 
    207  bool DispatchLoadScript(ScriptLoadRequest* aRequest);
    208 
    209  bool DispatchLoadScripts(
    210      nsTArray<RefPtr<ThreadSafeRequestHandle>>&& aLoadingList = {});
    211 
    212  void TryShutdown();
    213 
    214  WorkerScriptType GetWorkerScriptType() { return mWorkerScriptType; }
    215 
    216 protected:
    217  nsIURI* GetBaseURI() const override;
    218 
    219  nsIURI* GetInitialBaseURI();
    220 
    221  nsIGlobalObject* GetGlobal();
    222 
    223  void MaybeMoveToLoadedList(ScriptLoadRequest* aRequest);
    224 
    225  bool StoreCSP();
    226 
    227  bool ProcessPendingRequests(JSContext* aCx);
    228 
    229  bool AllScriptsExecuted() {
    230    return mLoadingRequests.isEmpty() && mLoadedRequests.isEmpty();
    231  }
    232 
    233  bool IsDebuggerScript() const { return mWorkerScriptType == DebuggerScript; }
    234 
    235  void SetController(const Maybe<ServiceWorkerDescriptor>& aDescriptor) {
    236    mController = aDescriptor;
    237  }
    238 
    239  Maybe<ServiceWorkerDescriptor>& GetController() { return mController; }
    240 
    241  nsresult LoadScript(ThreadSafeRequestHandle* aRequestHandle);
    242 
    243  void ShutdownScriptLoader(bool aResult, bool aMutedError);
    244 
    245 private:
    246  WorkerScriptLoader(UniquePtr<SerializedStackHolder> aOriginStack,
    247                     nsISerialEventTarget* aSyncLoopTarget,
    248                     WorkerScriptType aWorkerScriptType, ErrorResult& aRv);
    249 
    250  ~WorkerScriptLoader() = default;
    251 
    252  NS_IMETHOD
    253  GetName(nsACString& aName) override {
    254    aName.AssignLiteral("WorkerScriptLoader");
    255    return NS_OK;
    256  }
    257 
    258  void InitModuleLoader();
    259 
    260  nsTArray<RefPtr<ThreadSafeRequestHandle>> GetLoadingList();
    261 
    262  bool IsDynamicImport(ScriptLoadRequest* aRequest);
    263 
    264  nsContentPolicyType GetContentPolicyType(ScriptLoadRequest* aRequest);
    265 
    266  bool EvaluateScript(JSContext* aCx, ScriptLoadRequest* aRequest);
    267 
    268  nsresult FillCompileOptionsForRequest(
    269      JSContext* cx, ScriptLoadRequest* aRequest, JS::CompileOptions* aOptions,
    270      JS::MutableHandle<JSScript*> aIntroductionScript) override;
    271 
    272  void ReportErrorToConsole(ScriptLoadRequest* aRequest,
    273                            nsresult aResult) const override;
    274 
    275  // Only used by import maps, crash if we get here.
    276  void ReportWarningToConsole(
    277      ScriptLoadRequest* aRequest, const char* aMessageName,
    278      const nsTArray<nsString>& aParams = nsTArray<nsString>()) const override {
    279    MOZ_CRASH("Import maps have not been implemented for this context");
    280  }
    281 
    282  void LogExceptionToConsole(JSContext* aCx, WorkerPrivate* aWorkerPrivate);
    283 
    284  bool AllModuleRequestsLoaded() const;
    285  void IncreaseLoadingModuleRequestCount();
    286  void DecreaseLoadingModuleRequestCount();
    287 };
    288 
    289 /* ScriptLoaderRunnable
    290 *
    291 * Responsibilities of this class:
    292 *   - the actual dispatch
    293 *   - delegating the load back to WorkerScriptLoader
    294 *   - handling the collections of scripts being requested
    295 *   - handling main thread cancellation
    296 *   - dispatching back to the worker thread
    297 */
    298 class ScriptLoaderRunnable final : public nsIRunnable, public nsINamed {
    299  RefPtr<WorkerScriptLoader> mScriptLoader;
    300  RefPtr<ThreadSafeWorkerRef> mWorkerRef;
    301  nsTArrayView<RefPtr<ThreadSafeRequestHandle>> mLoadingRequests;
    302  Maybe<nsresult> mCancelMainThread;
    303  RefPtr<CacheCreator> mCacheCreator;
    304 
    305 public:
    306  NS_DECL_THREADSAFE_ISUPPORTS
    307 
    308  explicit ScriptLoaderRunnable(
    309      WorkerScriptLoader* aScriptLoader,
    310      nsTArray<RefPtr<ThreadSafeRequestHandle>> aLoadingRequests);
    311 
    312  nsresult OnStreamComplete(ThreadSafeRequestHandle* aRequestHandle,
    313                            nsresult aStatus);
    314 
    315  void LoadingFinished(ThreadSafeRequestHandle* aRequestHandle, nsresult aRv);
    316 
    317  void MaybeExecuteFinishedScripts(ThreadSafeRequestHandle* aRequestHandle);
    318 
    319  bool IsCancelled() { return mCancelMainThread.isSome(); }
    320 
    321  nsresult GetCancelResult() {
    322    return (IsCancelled()) ? mCancelMainThread.ref() : NS_OK;
    323  }
    324 
    325  void CancelMainThreadWithBindingAborted();
    326 
    327  CacheCreator* GetCacheCreator() { return mCacheCreator; };
    328 
    329 private:
    330  ~ScriptLoaderRunnable() = default;
    331 
    332  void CancelMainThread(nsresult aCancelResult);
    333 
    334  void DispatchProcessPendingRequests();
    335 
    336  NS_IMETHOD
    337  Run() override;
    338 
    339  NS_IMETHOD
    340  GetName(nsACString& aName) override {
    341    aName.AssignLiteral("ScriptLoaderRunnable");
    342    return NS_OK;
    343  }
    344 };
    345 
    346 }  // namespace loader
    347 
    348 nsresult ChannelFromScriptURLMainThread(
    349    nsIPrincipal* aPrincipal, Document* aParentDoc, nsILoadGroup* aLoadGroup,
    350    nsIURI* aScriptURL, const WorkerType& aWorkerType,
    351    const RequestCredentials& aCredentials,
    352    const Maybe<ClientInfo>& aClientInfo,
    353    nsContentPolicyType aContentPolicyType,
    354    nsICookieJarSettings* aCookieJarSettings, nsIReferrerInfo* aReferrerInfo,
    355    nsIChannel** aChannel);
    356 
    357 nsresult ChannelFromScriptURLWorkerThread(
    358    JSContext* aCx, WorkerPrivate* aParent, const nsAString& aScriptURL,
    359    const WorkerType& aWorkerType, const RequestCredentials& aCredentials,
    360    WorkerLoadInfo& aLoadInfo);
    361 
    362 void ReportLoadError(ErrorResult& aRv, nsresult aLoadResult,
    363                     const nsAString& aScriptURL);
    364 
    365 void LoadMainScript(WorkerPrivate* aWorkerPrivate,
    366                    UniquePtr<SerializedStackHolder> aOriginStack,
    367                    const nsAString& aScriptURL,
    368                    WorkerScriptType aWorkerScriptType, ErrorResult& aRv,
    369                    const mozilla::Encoding* aDocumentEncoding);
    370 
    371 void Load(WorkerPrivate* aWorkerPrivate,
    372          UniquePtr<SerializedStackHolder> aOriginStack,
    373          const nsTArray<nsString>& aScriptURLs,
    374          WorkerScriptType aWorkerScriptType, ErrorResult& aRv);
    375 
    376 }  // namespace workerinternals
    377 
    378 }  // namespace dom
    379 }  // namespace mozilla
    380 
    381 #endif /* mozilla_dom_workers_scriptloader_h__ */