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__ */