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