Bug 1800496 - Introduce ThreadSafeRequestHandle; r=asuth

This introduces a new datastructure that wraps the ScriptLoadRequest. Previously, we were using the WorkerLoadContext to access the request, and we made it not cycle collected in order to make it safe across threads. This, of course, broke module behavior, as the cycle needs to be broken in more places, and things get rather complex.

In the spirit of making everyone's life easier, the ThreadSafeRequestHandle exists as a way to move the request to the main thread, operate on it, and then return it to the worker. We no longer need to track and free the WorkerLoadContext. Once the ThreadSafeRequestHandle is returned to the worker, we release the request, and the handle is empty. There is a possibility that this will cause issues, so we should keep an eye on this. Alternatively, we can never release the ScriptLoadRequest and let the ThreadSafeRequestHandle clean it up on destruction.

In the case that we somehow end up releasing on the main thread, we will send a runnable to release the request correctly on the worker.

Differential Revision: https://phabricator.services.mozilla.com/D162213
This commit is contained in:
Yulia Startsev 2022-11-18 10:02:25 +00:00
Родитель b122d68410
Коммит 2310f5b5b6
8 изменённых файлов: 237 добавлений и 151 удалений

Просмотреть файл

@ -352,13 +352,13 @@ namespace loader {
class ScriptExecutorRunnable final : public MainThreadWorkerSyncRunnable {
RefPtr<WorkerScriptLoader> mScriptLoader;
RefPtr<WorkerLoadContext> mLoadContext;
RefPtr<ThreadSafeRequestHandle> mRequestHandle;
public:
ScriptExecutorRunnable(WorkerScriptLoader* aScriptLoader,
WorkerPrivate* aWorkerPrivate,
nsISerialEventTarget* aSyncLoopTarget,
WorkerLoadContext* aLoadContext);
ThreadSafeRequestHandle* aRequestHandle);
private:
~ScriptExecutorRunnable() = default;
@ -422,10 +422,11 @@ WorkerScriptLoader::WorkerScriptLoader(
// released by the ScriptLoader. In other words, something has caused
// the process to close and we have no control over it. We cannot wait
// for a safe cleanup. This usually impacts service workers.
nsTArray<WorkerLoadContext*> scriptLoadList = self->GetLoadingList();
nsTArray<ThreadSafeRequestHandle*> scriptLoadList =
self->GetLoadingList();
// Dispatch to clear out any service worker promises that may be running
NS_DispatchToMainThread(
NewRunnableMethod<nsTArray<WorkerLoadContext*>&&>(
NewRunnableMethod<nsTArray<ThreadSafeRequestHandle*>&&>(
"WorkerScriptLoader::CancelMainThreadWithBindingAborted", self,
&WorkerScriptLoader::CancelMainThreadWithBindingAborted,
std::move(scriptLoadList)));
@ -453,11 +454,14 @@ void WorkerScriptLoader::CreateScriptRequests(
}
}
nsTArray<WorkerLoadContext*> WorkerScriptLoader::GetLoadingList() {
nsTArray<WorkerLoadContext*> list;
nsTArray<ThreadSafeRequestHandle*> WorkerScriptLoader::GetLoadingList() {
mWorkerRef->Private()->AssertIsOnWorkerThread();
nsTArray<ThreadSafeRequestHandle*> list;
for (ScriptLoadRequest* req = mLoadingRequests.getFirst(); req;
req = req->getNext()) {
list.AppendElement(req->GetWorkerLoadContext());
ThreadSafeRequestHandle* handle =
new ThreadSafeRequestHandle(req, mSyncLoopTarget.get());
list.AppendElement(handle);
}
return list;
}
@ -507,11 +511,13 @@ already_AddRefed<ScriptLoadRequest> WorkerScriptLoader::CreateScriptLoadRequest(
bool WorkerScriptLoader::DispatchLoadScript(ScriptLoadRequest* aRequest) {
mWorkerRef->Private()->AssertIsOnWorkerThread();
nsTArray<WorkerLoadContext*> scriptLoadList;
scriptLoadList.AppendElement(aRequest->GetWorkerLoadContext());
nsTArray<ThreadSafeRequestHandle*> scriptLoadList;
ThreadSafeRequestHandle* handle =
new ThreadSafeRequestHandle(aRequest, mSyncLoopTarget.get());
scriptLoadList.AppendElement(handle);
nsresult rv =
NS_DispatchToMainThread(NewRunnableMethod<nsTArray<WorkerLoadContext*>&&>(
nsresult rv = NS_DispatchToMainThread(
NewRunnableMethod<nsTArray<ThreadSafeRequestHandle*>&&>(
"WorkerScriptLoader::LoadScripts", this,
&WorkerScriptLoader::LoadScripts, std::move(scriptLoadList)));
@ -526,10 +532,10 @@ bool WorkerScriptLoader::DispatchLoadScript(ScriptLoadRequest* aRequest) {
bool WorkerScriptLoader::DispatchLoadScripts() {
mWorkerRef->Private()->AssertIsOnWorkerThread();
nsTArray<WorkerLoadContext*> scriptLoadList = GetLoadingList();
nsTArray<ThreadSafeRequestHandle*> scriptLoadList = GetLoadingList();
nsresult rv =
NS_DispatchToMainThread(NewRunnableMethod<nsTArray<WorkerLoadContext*>&&>(
nsresult rv = NS_DispatchToMainThread(
NewRunnableMethod<nsTArray<ThreadSafeRequestHandle*>&&>(
"WorkerScriptLoader::LoadScripts", this,
&WorkerScriptLoader::LoadScripts, std::move(scriptLoadList)));
@ -572,15 +578,15 @@ nsIGlobalObject* WorkerScriptLoader::GetGlobal() {
: mWorkerRef->Private()->DebuggerGlobalScope();
}
void WorkerScriptLoader::LoadingFinished(ScriptLoadRequest* aRequest,
nsresult aRv) {
void WorkerScriptLoader::LoadingFinished(
ThreadSafeRequestHandle* aRequestHandle, nsresult aRv) {
AssertIsOnMainThread();
if (IsCancelled()) {
return;
}
WorkerLoadContext* loadContext = aRequest->GetWorkerLoadContext();
WorkerLoadContext* loadContext = aRequestHandle->GetContext();
loadContext->mLoadResult = aRv;
MOZ_ASSERT(!loadContext->mLoadingFinished);
@ -591,19 +597,19 @@ void WorkerScriptLoader::LoadingFinished(ScriptLoadRequest* aRequest,
mWorkerRef->Private()->PrincipalURIMatchesScriptURL());
}
MaybeExecuteFinishedScripts(aRequest);
MaybeExecuteFinishedScripts(aRequestHandle);
}
void WorkerScriptLoader::MaybeExecuteFinishedScripts(
ScriptLoadRequest* aRequest) {
ThreadSafeRequestHandle* aRequestHandle) {
AssertIsOnMainThread();
// We execute the last step if we don't have a pending operation with the
// cache and the loading is completed.
WorkerLoadContext* loadContext = aRequest->GetWorkerLoadContext();
WorkerLoadContext* loadContext = aRequestHandle->GetContext();
if (!loadContext->IsAwaitingPromise()) {
loadContext->ClearCacheCreator();
DispatchMaybeMoveToLoadedList(aRequest);
DispatchMaybeMoveToLoadedList(aRequestHandle);
}
}
@ -682,25 +688,25 @@ bool WorkerScriptLoader::ProcessPendingRequests(JSContext* aCx) {
return true;
}
nsresult WorkerScriptLoader::OnStreamComplete(ScriptLoadRequest* aRequest,
nsresult aStatus) {
nsresult WorkerScriptLoader::OnStreamComplete(
ThreadSafeRequestHandle* aRequestHandle, nsresult aStatus) {
AssertIsOnMainThread();
// We expect our callers to runtime-check this in advance.
MOZ_ASSERT(!IsCancelled());
LoadingFinished(aRequest, aStatus);
LoadingFinished(aRequestHandle, aStatus);
return NS_OK;
}
void WorkerScriptLoader::CancelMainThreadWithBindingAborted(
nsTArray<WorkerLoadContext*>&& aContextList) {
nsTArray<ThreadSafeRequestHandle*>&& aContextList) {
AssertIsOnMainThread();
CancelMainThread(NS_BINDING_ABORTED, &aContextList);
}
void WorkerScriptLoader::CancelMainThread(
nsresult aCancelResult, nsTArray<WorkerLoadContext*>* aContextList) {
nsresult aCancelResult, nsTArray<ThreadSafeRequestHandle*>* aContextList) {
AssertIsOnMainThread();
{
MutexAutoLock lock(CleanUpLock());
@ -714,10 +720,14 @@ void WorkerScriptLoader::CancelMainThread(
mCancelMainThread = Some(aCancelResult);
bool shouldDispatch = false;
for (WorkerLoadContext* loadContext : *aContextList) {
for (ThreadSafeRequestHandle* handle : *aContextList) {
if (handle->IsEmpty()) {
continue;
}
// In the case of a cancellation, service workers fetching from the
// cache will still be doing work despite CancelMainThread. Eagerly
// clear the promises associated with these scripts.
WorkerLoadContext* loadContext = handle->GetContext();
if (!loadContext) {
continue;
}
@ -743,7 +753,7 @@ void WorkerScriptLoader::CancelMainThread(
}
nsresult WorkerScriptLoader::LoadScripts(
nsTArray<WorkerLoadContext*>&& aContextList) {
nsTArray<ThreadSafeRequestHandle*>&& aContextList) {
AssertIsOnMainThread();
// Convert the origin stack to JSON (which must be done on the main
@ -754,10 +764,10 @@ nsresult WorkerScriptLoader::LoadScripts(
}
if (!mWorkerRef->Private()->IsServiceWorker() || IsDebuggerScript()) {
for (WorkerLoadContext* loadContext : aContextList) {
nsresult rv = LoadScript(loadContext->mRequest);
for (ThreadSafeRequestHandle* handle : aContextList) {
nsresult rv = LoadScript(handle);
if (NS_WARN_IF(NS_FAILED(rv))) {
LoadingFinished(loadContext->mRequest, rv);
LoadingFinished(handle, rv);
CancelMainThread(rv, &aContextList);
return rv;
}
@ -768,10 +778,11 @@ nsresult WorkerScriptLoader::LoadScripts(
RefPtr<CacheCreator> cacheCreator = new CacheCreator(mWorkerRef->Private());
for (WorkerLoadContext* loadContext : aContextList) {
for (ThreadSafeRequestHandle* handle : aContextList) {
WorkerLoadContext* loadContext = handle->GetContext();
loadContext->SetCacheCreator(cacheCreator);
loadContext->GetCacheCreator()->AddLoader(
MakeNotNull<RefPtr<CacheLoadHandler>>(mWorkerRef, loadContext->mRequest,
MakeNotNull<RefPtr<CacheLoadHandler>>(mWorkerRef, handle,
loadContext->IsTopLevel(), this));
}
@ -793,10 +804,11 @@ nsresult WorkerScriptLoader::LoadScripts(
return NS_OK;
}
nsresult WorkerScriptLoader::LoadScript(ScriptLoadRequest* aRequest) {
nsresult WorkerScriptLoader::LoadScript(
ThreadSafeRequestHandle* aRequestHandle) {
AssertIsOnMainThread();
WorkerLoadContext* loadContext = aRequest->GetWorkerLoadContext();
WorkerLoadContext* loadContext = aRequestHandle->GetContext();
MOZ_ASSERT_IF(loadContext->IsTopLevel(), !IsDebuggerScript());
// The URL passed to us for loading was invalid, stop loading at this point.
@ -872,8 +884,8 @@ nsresult WorkerScriptLoader::LoadScript(ScriptLoadRequest* aRequest) {
rv = ChannelFromScriptURL(
principal, parentDoc, mWorkerRef->Private(), loadGroup, ios, secMan,
aRequest->mURI, loadContext->mClientInfo, mController,
loadContext->IsTopLevel(), mWorkerScriptType,
aRequestHandle->GetRequest()->mURI, loadContext->mClientInfo,
mController, loadContext->IsTopLevel(), mWorkerScriptType,
mWorkerRef->Private()->ContentPolicyType(), loadFlags,
mWorkerRef->Private()->CookieJarSettings(), referrerInfo,
getter_AddRefs(channel));
@ -889,7 +901,8 @@ nsresult WorkerScriptLoader::LoadScript(ScriptLoadRequest* aRequest) {
// We need to know which index we're on in OnStreamComplete so we know
// where to put the result.
RefPtr<NetworkLoadHandler> listener = new NetworkLoadHandler(this, aRequest);
RefPtr<NetworkLoadHandler> listener =
new NetworkLoadHandler(this, aRequestHandle);
RefPtr<ScriptResponseHeaderProcessor> headerProcessor = nullptr;
@ -972,16 +985,15 @@ nsresult WorkerScriptLoader::LoadScript(ScriptLoadRequest* aRequest) {
}
void WorkerScriptLoader::DispatchMaybeMoveToLoadedList(
ScriptLoadRequest* aRequest) {
ThreadSafeRequestHandle* aRequestHandle) {
AssertIsOnMainThread();
if (aRequest->GetWorkerLoadContext()->IsTopLevel()) {
if (aRequestHandle->GetContext()->IsTopLevel()) {
mWorkerRef->Private()->WorkerScriptLoaded();
}
RefPtr<ScriptExecutorRunnable> runnable =
new ScriptExecutorRunnable(this, mWorkerRef->Private(), mSyncLoopTarget,
aRequest->GetWorkerLoadContext());
RefPtr<ScriptExecutorRunnable> runnable = new ScriptExecutorRunnable(
this, mWorkerRef->Private(), mSyncLoopTarget, aRequestHandle);
if (!runnable->Dispatch()) {
MOZ_ASSERT(false, "This should never fail!");
}
@ -1216,10 +1228,11 @@ bool AbruptCancellationRunnable::WorkerRun(JSContext* aCx,
ScriptExecutorRunnable::ScriptExecutorRunnable(
WorkerScriptLoader* aScriptLoader, WorkerPrivate* aWorkerPrivate,
nsISerialEventTarget* aSyncLoopTarget, WorkerLoadContext* aLoadContext)
nsISerialEventTarget* aSyncLoopTarget,
ThreadSafeRequestHandle* aRequestHandle)
: MainThreadWorkerSyncRunnable(aWorkerPrivate, aSyncLoopTarget),
mScriptLoader(aScriptLoader),
mLoadContext(aLoadContext) {}
mRequestHandle(aRequestHandle) {}
bool ScriptExecutorRunnable::IsDebuggerRunnable() const {
// ScriptExecutorRunnable is used to execute both worker and debugger scripts.
@ -1236,7 +1249,7 @@ bool ScriptExecutorRunnable::PreRun(WorkerPrivate* aWorkerPrivate) {
mScriptLoader->mSyncLoopTarget == mSyncLoopTarget,
"Unexpected SyncLoopTarget. Check if the sync loop was closed early");
if (!mLoadContext->IsTopLevel()) {
if (!mRequestHandle->GetContext()->IsTopLevel()) {
return true;
}
@ -1262,9 +1275,13 @@ bool ScriptExecutorRunnable::WorkerRun(JSContext* aCx,
"Unexpected SyncLoopTarget. Check if the sync loop was closed early");
// The request must be valid.
MOZ_ASSERT(mLoadContext->mRequest);
MOZ_ASSERT(!mRequestHandle->IsEmpty());
mScriptLoader->MaybeMoveToLoadedList(mLoadContext->mRequest);
// Release the request to the worker. From this point on, the Request Handle
// is empty.
RefPtr<ScriptLoadRequest> request = mRequestHandle->ReleaseRequest();
mScriptLoader->MaybeMoveToLoadedList(request);
return mScriptLoader->ProcessPendingRequests(aCx);
}

Просмотреть файл

@ -10,6 +10,7 @@
#include "js/loader/ScriptLoadRequest.h"
#include "js/loader/ModuleLoaderBase.h"
#include "mozilla/dom/WorkerCommon.h"
#include "mozilla/dom/WorkerLoadContext.h"
#include "mozilla/dom/WorkerRef.h"
#include "mozilla/Maybe.h"
#include "nsIContentPolicy.h"
@ -168,7 +169,7 @@ class WorkerScriptLoader : public JS::loader::ScriptLoaderInterface,
WorkerScriptType aWorkerScriptType, ErrorResult& aRv);
void CancelMainThreadWithBindingAborted(
nsTArray<WorkerLoadContext*>&& aContextList);
nsTArray<ThreadSafeRequestHandle*>&& aContextList);
void CreateScriptRequests(const nsTArray<nsString>& aScriptURLs,
const mozilla::Encoding* aDocumentEncoding,
@ -187,7 +188,7 @@ class WorkerScriptLoader : public JS::loader::ScriptLoaderInterface,
nsIURI* GetInitialBaseURI();
void MaybeExecuteFinishedScripts(ScriptLoadRequest* aRequest);
void MaybeExecuteFinishedScripts(ThreadSafeRequestHandle* aRequestHandle);
void MaybeMoveToLoadedList(ScriptLoadRequest* aRequest);
@ -199,7 +200,8 @@ class WorkerScriptLoader : public JS::loader::ScriptLoaderInterface,
return mLoadingRequests.isEmpty() && mLoadedRequests.isEmpty();
}
nsresult OnStreamComplete(ScriptLoadRequest* aRequest, nsresult aStatus);
nsresult OnStreamComplete(ThreadSafeRequestHandle* aRequestHandle,
nsresult aStatus);
bool IsDebuggerScript() const { return mWorkerScriptType == DebuggerScript; }
@ -216,11 +218,11 @@ class WorkerScriptLoader : public JS::loader::ScriptLoaderInterface,
}
void CancelMainThread(nsresult aCancelResult,
nsTArray<WorkerLoadContext*>* aContextList);
nsTArray<ThreadSafeRequestHandle*>* aContextList);
nsresult LoadScripts(nsTArray<WorkerLoadContext*>&& aContextList);
nsresult LoadScripts(nsTArray<ThreadSafeRequestHandle*>&& aContextList);
nsresult LoadScript(ScriptLoadRequest* aRequest);
nsresult LoadScript(ThreadSafeRequestHandle* aRequestHandle);
void ShutdownScriptLoader(bool aResult, bool aMutedError);
@ -239,15 +241,14 @@ class WorkerScriptLoader : public JS::loader::ScriptLoaderInterface,
void DispatchAbruptShutdown();
nsTArray<WorkerLoadContext*> GetLoadingList();
nsTArray<ThreadSafeRequestHandle*> GetLoadingList();
nsIGlobalObject* GetGlobal();
void LoadingFinished(ScriptLoadRequest* aRequest, nsresult aRv);
void LoadingFinished(ThreadSafeRequestHandle* aRequestHandle, nsresult aRv);
void DispatchMaybeMoveToLoadedList(ScriptLoadRequest* aRequest);
void DispatchMaybeMoveToLoadedList(ThreadSafeRequestHandle* aRequestHandle);
bool HasLoadErrors(WorkerLoadContext* aLoadContext);
bool EvaluateScript(JSContext* aCx, ScriptLoadRequest* aRequest);
nsresult FillCompileOptionsForRequest(

Просмотреть файл

@ -40,9 +40,9 @@ NS_IMPL_ISUPPORTS(CacheLoadHandler, nsIStreamLoaderObserver)
NS_IMPL_ISUPPORTS0(CachePromiseHandler)
CachePromiseHandler::CachePromiseHandler(WorkerScriptLoader* aLoader,
WorkerLoadContext* aLoadContext)
: mLoader(aLoader), mLoadContext(aLoadContext) {
CachePromiseHandler::CachePromiseHandler(
WorkerScriptLoader* aLoader, ThreadSafeRequestHandle* aRequestHandle)
: mLoader(aLoader), mRequestHandle(aRequestHandle) {
AssertIsOnMainThread();
MOZ_ASSERT(mLoader);
}
@ -51,18 +51,21 @@ void CachePromiseHandler::ResolvedCallback(JSContext* aCx,
JS::Handle<JS::Value> aValue,
ErrorResult& aRv) {
AssertIsOnMainThread();
MOZ_ASSERT(!mRequestHandle->IsEmpty());
WorkerLoadContext* loadContext = mRequestHandle->GetContext();
// May already have been canceled by CacheLoadHandler::Fail from
// CancelMainThread.
MOZ_ASSERT(mLoadContext->mCacheStatus == WorkerLoadContext::WritingToCache ||
mLoadContext->mCacheStatus == WorkerLoadContext::Cancel);
MOZ_ASSERT_IF(mLoadContext->mCacheStatus == WorkerLoadContext::Cancel,
!mLoadContext->mCachePromise);
MOZ_ASSERT(loadContext->mCacheStatus == WorkerLoadContext::WritingToCache ||
loadContext->mCacheStatus == WorkerLoadContext::Cancel);
MOZ_ASSERT_IF(loadContext->mCacheStatus == WorkerLoadContext::Cancel,
!loadContext->mCachePromise);
if (mLoadContext->mCachePromise) {
mLoadContext->mCacheStatus = WorkerLoadContext::Cached;
mLoadContext->mCachePromise = nullptr;
if (mLoadContext->mRequest) {
mLoader->MaybeExecuteFinishedScripts(mLoadContext->mRequest);
if (loadContext->mCachePromise) {
loadContext->mCacheStatus = WorkerLoadContext::Cached;
loadContext->mCachePromise = nullptr;
if (loadContext->mRequest) {
mLoader->MaybeExecuteFinishedScripts(mRequestHandle);
}
}
}
@ -71,17 +74,20 @@ void CachePromiseHandler::RejectedCallback(JSContext* aCx,
JS::Handle<JS::Value> aValue,
ErrorResult& aRv) {
AssertIsOnMainThread();
MOZ_ASSERT(!mRequestHandle->IsEmpty());
WorkerLoadContext* loadContext = mRequestHandle->GetContext();
// May already have been canceled by CacheLoadHandler::Fail from
// CancelMainThread.
MOZ_ASSERT(mLoadContext->mCacheStatus == WorkerLoadContext::WritingToCache ||
mLoadContext->mCacheStatus == WorkerLoadContext::Cancel);
mLoadContext->mCacheStatus = WorkerLoadContext::Cancel;
MOZ_ASSERT(loadContext->mCacheStatus == WorkerLoadContext::WritingToCache ||
loadContext->mCacheStatus == WorkerLoadContext::Cancel);
loadContext->mCacheStatus = WorkerLoadContext::Cancel;
mLoadContext->mCachePromise = nullptr;
loadContext->mCachePromise = nullptr;
// This will delete the cache object and will call LoadingFinished() with an
// error for each ongoing operation.
auto cacheCreator = mLoadContext->GetCacheCreator();
auto cacheCreator = loadContext->GetCacheCreator();
if (cacheCreator) {
cacheCreator->DeleteCache(NS_ERROR_FAILURE);
}
@ -226,10 +232,10 @@ void CacheCreator::DeleteCache(nsresult aReason) {
}
CacheLoadHandler::CacheLoadHandler(ThreadSafeWorkerRef* aWorkerRef,
JS::loader::ScriptLoadRequest* aRequest,
ThreadSafeRequestHandle* aRequestHandle,
bool aIsWorkerScript,
WorkerScriptLoader* aLoader)
: mLoadContext(aRequest->GetWorkerLoadContext()),
: mRequestHandle(aRequestHandle),
mLoader(aLoader),
mWorkerRef(aWorkerRef),
mIsWorkerScript(aIsWorkerScript),
@ -249,6 +255,8 @@ CacheLoadHandler::CacheLoadHandler(ThreadSafeWorkerRef* aWorkerRef,
void CacheLoadHandler::Fail(nsresult aRv) {
AssertIsOnMainThread();
MOZ_ASSERT(!mRequestHandle->IsEmpty());
WorkerLoadContext* loadContext = mRequestHandle->GetContext();
MOZ_ASSERT(NS_FAILED(aRv));
if (mFailed) {
@ -258,41 +266,41 @@ void CacheLoadHandler::Fail(nsresult aRv) {
mFailed = true;
if (mPump) {
MOZ_ASSERT(mLoadContext->mCacheStatus ==
MOZ_ASSERT(loadContext->mCacheStatus ==
WorkerLoadContext::ReadingFromCache);
mPump->Cancel(aRv);
mPump = nullptr;
}
mLoadContext->mCacheStatus = WorkerLoadContext::Cancel;
loadContext->mCacheStatus = WorkerLoadContext::Cancel;
if (mLoadContext->mCachePromise) {
mLoadContext->mCachePromise->MaybeReject(aRv);
if (loadContext->mCachePromise) {
loadContext->mCachePromise->MaybeReject(aRv);
}
mLoadContext->mCachePromise = nullptr;
loadContext->mCachePromise = nullptr;
mLoadContext->ClearCacheCreator();
if (mLoader->IsCancelled() || !mLoadContext->mRequest) {
loadContext->ClearCacheCreator();
if (mLoader->IsCancelled() || !loadContext->mRequest) {
return;
}
mLoader->LoadingFinished(mLoadContext->mRequest, aRv);
mLoader->LoadingFinished(mRequestHandle, aRv);
}
void CacheLoadHandler::Load(Cache* aCache) {
AssertIsOnMainThread();
MOZ_ASSERT(aCache);
MOZ_ASSERT(!mRequestHandle->IsEmpty());
WorkerLoadContext* loadContext = mRequestHandle->GetContext();
if (mLoader->IsCancelled()) {
Fail(NS_BINDING_ABORTED);
return;
}
MOZ_ASSERT(mLoadContext->mRequest);
nsCOMPtr<nsIURI> uri;
nsresult rv = NS_NewURI(getter_AddRefs(uri), mLoadContext->mRequest->mURL,
nsresult rv = NS_NewURI(getter_AddRefs(uri), loadContext->mRequest->mURL,
nullptr, mBaseURI);
if (NS_WARN_IF(NS_FAILED(rv))) {
Fail(rv);
@ -306,11 +314,11 @@ void CacheLoadHandler::Load(Cache* aCache) {
return;
}
MOZ_ASSERT(mLoadContext->mFullURL.IsEmpty());
CopyUTF8toUTF16(spec, mLoadContext->mFullURL);
MOZ_ASSERT(loadContext->mFullURL.IsEmpty());
CopyUTF8toUTF16(spec, loadContext->mFullURL);
mozilla::dom::RequestOrUSVString request;
request.SetAsUSVString().ShareOrDependUpon(mLoadContext->mFullURL);
request.SetAsUSVString().ShareOrDependUpon(loadContext->mFullURL);
mozilla::dom::CacheQueryOptions params;
@ -333,8 +341,10 @@ void CacheLoadHandler::RejectedCallback(JSContext* aCx,
JS::Handle<JS::Value> aValue,
ErrorResult& aRv) {
AssertIsOnMainThread();
MOZ_ASSERT(!mRequestHandle->IsEmpty());
MOZ_ASSERT(mLoadContext->mCacheStatus == WorkerLoadContext::Uncached);
MOZ_ASSERT(mRequestHandle->GetContext()->mCacheStatus ==
WorkerLoadContext::Uncached);
Fail(NS_ERROR_FAILURE);
}
@ -342,6 +352,9 @@ void CacheLoadHandler::ResolvedCallback(JSContext* aCx,
JS::Handle<JS::Value> aValue,
ErrorResult& aRv) {
AssertIsOnMainThread();
MOZ_ASSERT(!mRequestHandle->IsEmpty());
WorkerLoadContext* loadContext = mRequestHandle->GetContext();
// If we have already called 'Fail', we should not proceed. If we cancelled,
// we should similarily not proceed.
if (mFailed) {
@ -352,7 +365,7 @@ void CacheLoadHandler::ResolvedCallback(JSContext* aCx,
return;
}
MOZ_ASSERT(mLoadContext->mCacheStatus == WorkerLoadContext::Uncached);
MOZ_ASSERT(loadContext->mCacheStatus == WorkerLoadContext::Uncached);
nsresult rv;
@ -374,8 +387,8 @@ void CacheLoadHandler::ResolvedCallback(JSContext* aCx,
return;
}
mLoadContext->mCacheStatus = WorkerLoadContext::ToBeCached;
rv = mLoader->LoadScript(mLoadContext->mRequest);
loadContext->mCacheStatus = WorkerLoadContext::ToBeCached;
rv = mLoader->LoadScript(mRequestHandle);
if (NS_WARN_IF(NS_FAILED(rv))) {
Fail(rv);
}
@ -409,7 +422,7 @@ void CacheLoadHandler::ResolvedCallback(JSContext* aCx,
OriginTrial::CoepCredentialless));
rv = ScriptResponseHeaderProcessor::ProcessCrossOriginEmbedderPolicyHeader(
mWorkerRef->Private(), coep, mLoadContext->IsTopLevel());
mWorkerRef->Private(), coep, loadContext->IsTopLevel());
if (NS_WARN_IF(NS_FAILED(rv))) {
Fail(rv);
@ -425,14 +438,14 @@ void CacheLoadHandler::ResolvedCallback(JSContext* aCx,
}
if (!inputStream) {
mLoadContext->mCacheStatus = WorkerLoadContext::Cached;
loadContext->mCacheStatus = WorkerLoadContext::Cached;
if (mLoader->IsCancelled()) {
auto cacheCreator = mLoadContext->GetCacheCreator();
auto cacheCreator = loadContext->GetCacheCreator();
if (cacheCreator) {
cacheCreator->DeleteCache(mLoader->GetCancelResult());
}
mLoadContext->ClearCacheCreator();
loadContext->ClearCacheCreator();
return;
}
@ -440,8 +453,8 @@ void CacheLoadHandler::ResolvedCallback(JSContext* aCx,
(uint8_t*)"", 0, mChannelInfo, std::move(mPrincipalInfo),
mCSPHeaderValue, mCSPReportOnlyHeaderValue, mReferrerPolicyHeaderValue);
mLoadContext->ClearCacheCreator();
mLoader->OnStreamComplete(mLoadContext->mRequest, rv);
loadContext->ClearCacheCreator();
mLoader->OnStreamComplete(mRequestHandle, rv);
return;
}
@ -480,7 +493,7 @@ void CacheLoadHandler::ResolvedCallback(JSContext* aCx,
}
}
mLoadContext->mCacheStatus = WorkerLoadContext::ReadingFromCache;
loadContext->mCacheStatus = WorkerLoadContext::ReadingFromCache;
}
NS_IMETHODIMP
@ -489,31 +502,33 @@ CacheLoadHandler::OnStreamComplete(nsIStreamLoader* aLoader,
uint32_t aStringLen,
const uint8_t* aString) {
AssertIsOnMainThread();
MOZ_ASSERT(!mRequestHandle->IsEmpty());
WorkerLoadContext* loadContext = mRequestHandle->GetContext();
mPump = nullptr;
if (NS_FAILED(aStatus)) {
MOZ_ASSERT(mLoadContext->mCacheStatus ==
MOZ_ASSERT(loadContext->mCacheStatus ==
WorkerLoadContext::ReadingFromCache ||
mLoadContext->mCacheStatus == WorkerLoadContext::Cancel);
loadContext->mCacheStatus == WorkerLoadContext::Cancel);
Fail(aStatus);
return NS_OK;
}
if (mLoader->IsCancelled() || !mLoadContext->mRequest) {
if (mLoader->IsCancelled() || !loadContext->mRequest) {
Fail(NS_BINDING_ABORTED);
return NS_OK;
}
MOZ_ASSERT(mLoadContext->mCacheStatus == WorkerLoadContext::ReadingFromCache);
mLoadContext->mCacheStatus = WorkerLoadContext::Cached;
MOZ_ASSERT(loadContext->mCacheStatus == WorkerLoadContext::ReadingFromCache);
loadContext->mCacheStatus = WorkerLoadContext::Cached;
MOZ_ASSERT(mPrincipalInfo);
nsresult rv = DataReceivedFromCache(
aString, aStringLen, mChannelInfo, std::move(mPrincipalInfo),
mCSPHeaderValue, mCSPReportOnlyHeaderValue, mReferrerPolicyHeaderValue);
return mLoader->OnStreamComplete(mLoadContext->mRequest, rv);
return mLoader->OnStreamComplete(mRequestHandle, rv);
}
nsresult CacheLoadHandler::DataReceivedFromCache(
@ -523,9 +538,11 @@ nsresult CacheLoadHandler::DataReceivedFromCache(
const nsACString& aCSPReportOnlyHeaderValue,
const nsACString& aReferrerPolicyHeaderValue) {
AssertIsOnMainThread();
MOZ_ASSERT(!mRequestHandle->IsEmpty());
WorkerLoadContext* loadContext = mRequestHandle->GetContext();
MOZ_ASSERT(mLoadContext->mCacheStatus == WorkerLoadContext::Cached);
MOZ_ASSERT(mLoadContext->mRequest);
MOZ_ASSERT(loadContext->mCacheStatus == WorkerLoadContext::Cached);
MOZ_ASSERT(loadContext->mRequest);
auto responsePrincipalOrErr = PrincipalInfoToPrincipal(*aPrincipalInfo);
MOZ_DIAGNOSTIC_ASSERT(responsePrincipalOrErr.isOk());
@ -539,8 +556,7 @@ nsresult CacheLoadHandler::DataReceivedFromCache(
nsCOMPtr<nsIPrincipal> responsePrincipal = responsePrincipalOrErr.unwrap();
mLoadContext->mMutedErrorFlag.emplace(
!principal->Subsumes(responsePrincipal));
loadContext->mMutedErrorFlag.emplace(!principal->Subsumes(responsePrincipal));
// May be null.
Document* parentDoc = mWorkerRef->Private()->GetDocument();
@ -550,21 +566,21 @@ nsresult CacheLoadHandler::DataReceivedFromCache(
nsresult rv;
// Set the Source type to "text" for decoding.
mLoadContext->mRequest->SetTextSource();
loadContext->mRequest->SetTextSource();
rv = mDecoder->DecodeRawData(mLoadContext->mRequest, aString, aStringLen,
rv = mDecoder->DecodeRawData(loadContext->mRequest, aString, aStringLen,
/* aEndOfStream = */ true);
NS_ENSURE_SUCCESS(rv, rv);
if (!mLoadContext->mRequest->ScriptTextLength()) {
if (!loadContext->mRequest->ScriptTextLength()) {
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, "DOM"_ns,
parentDoc, nsContentUtils::eDOM_PROPERTIES,
"EmptyWorkerSourceWarning");
}
if (mLoadContext->IsTopLevel()) {
if (loadContext->IsTopLevel()) {
nsCOMPtr<nsIURI> finalURI;
rv = NS_NewURI(getter_AddRefs(finalURI), mLoadContext->mFullURL);
rv = NS_NewURI(getter_AddRefs(finalURI), loadContext->mFullURL);
if (NS_SUCCEEDED(rv)) {
mWorkerRef->Private()->SetBaseURI(finalURI);
}
@ -617,7 +633,10 @@ nsresult CacheLoadHandler::DataReceivedFromCache(
}
void CacheLoadHandler::DataReceived() {
if (mLoadContext->IsTopLevel()) {
MOZ_ASSERT(!mRequestHandle->IsEmpty());
WorkerLoadContext* loadContext = mRequestHandle->GetContext();
if (loadContext->IsTopLevel()) {
WorkerPrivate* parent = mWorkerRef->Private()->GetParent();
if (parent) {

Просмотреть файл

@ -81,7 +81,7 @@ class CacheLoadHandler final : public PromiseNativeHandler,
NS_DECL_NSISTREAMLOADEROBSERVER
CacheLoadHandler(ThreadSafeWorkerRef* aWorkerRef,
JS::loader::ScriptLoadRequest* aRequest,
ThreadSafeRequestHandle* aRequestHandle,
bool aIsWorkerScript, WorkerScriptLoader* aLoader);
void Fail(nsresult aRv);
@ -105,7 +105,7 @@ class CacheLoadHandler final : public PromiseNativeHandler,
const nsACString& aReferrerPolicyHeaderValue);
void DataReceived();
RefPtr<WorkerLoadContext> mLoadContext;
RefPtr<ThreadSafeRequestHandle> mRequestHandle;
const RefPtr<WorkerScriptLoader> mLoader;
RefPtr<ThreadSafeWorkerRef> mWorkerRef;
const bool mIsWorkerScript;
@ -198,7 +198,7 @@ class CachePromiseHandler final : public PromiseNativeHandler {
NS_DECL_ISUPPORTS
CachePromiseHandler(WorkerScriptLoader* aLoader,
WorkerLoadContext* aLoadContext);
ThreadSafeRequestHandle* aRequestHandle);
virtual void ResolvedCallback(JSContext* aCx, JS::Handle<JS::Value> aValue,
ErrorResult& aRv) override;
@ -210,7 +210,7 @@ class CachePromiseHandler final : public PromiseNativeHandler {
~CachePromiseHandler() { AssertIsOnMainThread(); }
RefPtr<WorkerScriptLoader> mLoader;
RefPtr<WorkerLoadContext> mLoadContext;
RefPtr<ThreadSafeRequestHandle> mRequestHandle;
};
} // namespace workerinternals::loader

Просмотреть файл

@ -37,10 +37,10 @@ NS_IMPL_ISUPPORTS(NetworkLoadHandler, nsIStreamLoaderObserver,
nsIRequestObserver)
NetworkLoadHandler::NetworkLoadHandler(WorkerScriptLoader* aLoader,
JS::loader::ScriptLoadRequest* aRequest)
ThreadSafeRequestHandle* aRequestHandle)
: mLoader(aLoader),
mWorkerRef(aLoader->mWorkerRef),
mLoadContext(aRequest->GetWorkerLoadContext()) {
mRequestHandle(aRequestHandle) {
MOZ_ASSERT(mLoader);
// Worker scripts are always decoded as UTF-8 per spec.
@ -59,12 +59,12 @@ NetworkLoadHandler::OnStreamComplete(nsIStreamLoader* aLoader,
return mLoader->GetCancelResult();
}
if (!mLoadContext->mRequest) {
if (!mRequestHandle->IsEmpty()) {
return NS_BINDING_ABORTED;
}
nsresult rv = DataReceivedFromNetwork(aLoader, aStatus, aStringLen, aString);
return mLoader->OnStreamComplete(mLoadContext->mRequest, rv);
return mLoader->OnStreamComplete(mRequestHandle, rv);
}
nsresult NetworkLoadHandler::DataReceivedFromNetwork(nsIStreamLoader* aLoader,
@ -72,7 +72,8 @@ nsresult NetworkLoadHandler::DataReceivedFromNetwork(nsIStreamLoader* aLoader,
uint32_t aStringLen,
const uint8_t* aString) {
AssertIsOnMainThread();
MOZ_ASSERT(mLoadContext->mRequest);
MOZ_ASSERT(!mRequestHandle->IsEmpty());
WorkerLoadContext* loadContext = mRequestHandle->GetContext();
if (NS_FAILED(aStatus)) {
return aStatus;
@ -105,7 +106,7 @@ nsresult NetworkLoadHandler::DataReceivedFromNetwork(nsIStreamLoader* aLoader,
}
#ifdef DEBUG
if (mLoadContext->IsTopLevel()) {
if (loadContext->IsTopLevel()) {
nsCOMPtr<nsIPrincipal> loadingPrincipal =
mWorkerRef->Private()->GetLoadingPrincipal();
// if we are not in a ServiceWorker, and the principal is not null, then
@ -121,8 +122,8 @@ nsresult NetworkLoadHandler::DataReceivedFromNetwork(nsIStreamLoader* aLoader,
// same-origin checks on them so we should be able to see their errors.
// Note that for data: url, where we allow it through the same-origin check
// but then give it a different origin.
mLoadContext->mMutedErrorFlag.emplace(!mLoadContext->IsTopLevel() &&
!principal->Subsumes(channelPrincipal));
loadContext->mMutedErrorFlag.emplace(!loadContext->IsTopLevel() &&
!principal->Subsumes(channelPrincipal));
// Make sure we're not seeing the result of a 404 or something by checking
// the 'requestSucceeded' attribute on the http channel.
@ -149,7 +150,7 @@ nsresult NetworkLoadHandler::DataReceivedFromNetwork(nsIStreamLoader* aLoader,
nsAutoCString sourceMapURL;
if (nsContentUtils::GetSourceMapURL(httpChannel, sourceMapURL)) {
mLoadContext->mRequest->mSourceMapURL =
loadContext->mRequest->mSourceMapURL =
Some(NS_ConvertUTF8toUTF16(sourceMapURL));
}
}
@ -158,21 +159,21 @@ nsresult NetworkLoadHandler::DataReceivedFromNetwork(nsIStreamLoader* aLoader,
Document* parentDoc = mWorkerRef->Private()->GetDocument();
// Set the Source type to "text" for decoding.
mLoadContext->mRequest->SetTextSource();
loadContext->mRequest->SetTextSource();
// Use the regular ScriptDecoder Decoder for this grunt work! Should be just
// fine because we're running on the main thread.
rv = mDecoder->DecodeRawData(mLoadContext->mRequest, aString, aStringLen,
rv = mDecoder->DecodeRawData(loadContext->mRequest, aString, aStringLen,
/* aEndOfStream = */ true);
NS_ENSURE_SUCCESS(rv, rv);
if (!mLoadContext->mRequest->ScriptTextLength()) {
if (!loadContext->mRequest->ScriptTextLength()) {
nsContentUtils::ReportToConsole(nsIScriptError::warningFlag, "DOM"_ns,
parentDoc, nsContentUtils::eDOM_PROPERTIES,
"EmptyWorkerSourceWarning");
}
if (mLoadContext->mRequest->IsModuleRequest()) {
if (loadContext->mRequest->IsModuleRequest()) {
// For modules, we need to store the base URI on the module request object,
// rather than on the worker private (as we do for classic scripts). This is
// because module loading is shared across multiple components, with
@ -183,7 +184,7 @@ nsresult NetworkLoadHandler::DataReceivedFromNetwork(nsIStreamLoader* aLoader,
rv = channel->GetOriginalURI(getter_AddRefs(uri));
NS_ENSURE_SUCCESS(rv, rv);
channel->GetURI(getter_AddRefs(mLoadContext->mRequest->mBaseURL));
channel->GetURI(getter_AddRefs(loadContext->mRequest->mBaseURL));
}
// Figure out what we actually loaded.
@ -201,13 +202,13 @@ nsresult NetworkLoadHandler::DataReceivedFromNetwork(nsIStreamLoader* aLoader,
// in case of errors, and is used for debugging.
// The full URL shouldn't be exposed to the debugger if cross origin.
// See Bug 1634872.
mLoadContext->mRequest->mURL = filename;
loadContext->mRequest->mURL = filename;
}
}
// Update the principal of the worker and its base URI if we just loaded the
// worker's primary script.
if (mLoadContext->IsTopLevel()) {
if (loadContext->IsTopLevel()) {
// Take care of the base URI first.
mWorkerRef->Private()->SetBaseURI(finalURI);
@ -282,7 +283,8 @@ NetworkLoadHandler::OnStartRequest(nsIRequest* aRequest) {
nsresult NetworkLoadHandler::PrepareForRequest(nsIRequest* aRequest) {
AssertIsOnMainThread();
MOZ_ASSERT(mLoadContext->mRequest);
MOZ_ASSERT(!mRequestHandle->IsEmpty());
WorkerLoadContext* loadContext = mRequestHandle->GetContext();
// If one load info cancels or hits an error, it can race with the start
// callback coming from another load info.
@ -313,7 +315,7 @@ nsresult NetworkLoadHandler::PrepareForRequest(nsIRequest* aRequest) {
scope, "ServiceWorkerRegisterMimeTypeError2",
nsTArray<nsString>{
NS_ConvertUTF8toUTF16(scope), NS_ConvertUTF8toUTF16(mimeType),
NS_ConvertUTF8toUTF16(mLoadContext->mRequest->mURL)});
NS_ConvertUTF8toUTF16(loadContext->mRequest->mURL)});
return NS_ERROR_DOM_NETWORK_ERR;
}
@ -322,12 +324,12 @@ nsresult NetworkLoadHandler::PrepareForRequest(nsIRequest* aRequest) {
// We synthesize the result code, but its never exposed to content.
SafeRefPtr<mozilla::dom::InternalResponse> ir =
MakeSafeRefPtr<mozilla::dom::InternalResponse>(200, "OK"_ns);
ir->SetBody(mLoadContext->mCacheReadStream,
ir->SetBody(loadContext->mCacheReadStream,
InternalResponse::UNKNOWN_BODY_SIZE);
// Drop our reference to the stream now that we've passed it along, so it
// doesn't hang around once the cache is done with it and keep data alive.
mLoadContext->mCacheReadStream = nullptr;
loadContext->mCacheReadStream = nullptr;
// Set the channel info of the channel on the response so that it's
// saved in the cache.
@ -349,12 +351,12 @@ nsresult NetworkLoadHandler::PrepareForRequest(nsIRequest* aRequest) {
ir->Headers()->FillResponseHeaders(channel);
RefPtr<mozilla::dom::Response> response = new mozilla::dom::Response(
mLoadContext->GetCacheCreator()->Global(), std::move(ir), nullptr);
loadContext->GetCacheCreator()->Global(), std::move(ir), nullptr);
mozilla::dom::RequestOrUSVString request;
MOZ_ASSERT(!mLoadContext->mFullURL.IsEmpty());
request.SetAsUSVString().ShareOrDependUpon(mLoadContext->mFullURL);
MOZ_ASSERT(!loadContext->mFullURL.IsEmpty());
request.SetAsUSVString().ShareOrDependUpon(loadContext->mFullURL);
// This JSContext will not end up executing JS code because here there are
// no ReadableStreams involved.
@ -362,7 +364,7 @@ nsresult NetworkLoadHandler::PrepareForRequest(nsIRequest* aRequest) {
jsapi.Init();
ErrorResult error;
RefPtr<Promise> cachePromise = mLoadContext->GetCacheCreator()->Cache_()->Put(
RefPtr<Promise> cachePromise = loadContext->GetCacheCreator()->Cache_()->Put(
jsapi.cx(), request, *response, error);
error.WouldReportJSException();
if (NS_WARN_IF(error.Failed())) {
@ -370,11 +372,11 @@ nsresult NetworkLoadHandler::PrepareForRequest(nsIRequest* aRequest) {
}
RefPtr<CachePromiseHandler> promiseHandler =
new CachePromiseHandler(mLoader, mLoadContext);
new CachePromiseHandler(mLoader, mRequestHandle);
cachePromise->AppendNativeHandler(promiseHandler);
mLoadContext->mCachePromise.swap(cachePromise);
mLoadContext->mCacheStatus = WorkerLoadContext::WritingToCache;
loadContext->mCachePromise.swap(cachePromise);
loadContext->mCacheStatus = WorkerLoadContext::WritingToCache;
return NS_OK;
}

Просмотреть файл

@ -44,7 +44,7 @@ class NetworkLoadHandler final : public nsIStreamLoaderObserver,
NS_DECL_ISUPPORTS
NetworkLoadHandler(WorkerScriptLoader* aLoader,
JS::loader::ScriptLoadRequest* aRequest);
ThreadSafeRequestHandle* aRequestHandle);
NS_IMETHOD
OnStreamComplete(nsIStreamLoader* aLoader, nsISupports* aContext,
@ -71,7 +71,7 @@ class NetworkLoadHandler final : public nsIStreamLoaderObserver,
RefPtr<WorkerScriptLoader> mLoader;
UniquePtr<ScriptDecoder> mDecoder;
RefPtr<ThreadSafeWorkerRef> mWorkerRef;
RefPtr<WorkerLoadContext> mLoadContext;
RefPtr<ThreadSafeRequestHandle> mRequestHandle;
};
} // namespace mozilla::dom::workerinternals::loader

Просмотреть файл

@ -35,5 +35,30 @@ WorkerLoadContext::GetCacheCreator() {
return mCacheCreator.get();
}
ThreadSafeRequestHandle::ThreadSafeRequestHandle(
JS::loader::ScriptLoadRequest* aRequest, nsISerialEventTarget* aSyncTarget)
: mRequest(aRequest), mOwningEventTarget(aSyncTarget) {}
already_AddRefed<JS::loader::ScriptLoadRequest>
ThreadSafeRequestHandle::ReleaseRequest() {
return mRequest.forget();
}
ThreadSafeRequestHandle::~ThreadSafeRequestHandle() {
// Normally we only touch mStrongRef on the owning thread. This is safe,
// however, because when we do use mStrongRef on the owning thread we are
// always holding a strong ref to the ThreadsafeHandle via the owning
// runnable. So we cannot run the ThreadsafeHandle destructor simultaneously.
if (!mRequest || mOwningEventTarget->IsOnCurrentThread()) {
return;
}
// Dispatch in NS_ProxyRelease is guaranteed to succeed here because we block
// shutdown until all Contexts have been destroyed. Therefore it is ok to have
// MOZ_ALWAYS_SUCCEED here.
MOZ_ALWAYS_SUCCEEDS(NS_ProxyRelease("ThreadSafeRequestHandle::mRequest",
mOwningEventTarget, mRequest.forget()));
}
} // namespace dom
} // namespace mozilla

Просмотреть файл

@ -156,5 +156,27 @@ class WorkerLoadContext : public JS::loader::LoadContextNoCCBase {
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; }
already_AddRefed<JS::loader::ScriptLoadRequest> ReleaseRequest();
private:
~ThreadSafeRequestHandle();
RefPtr<JS::loader::ScriptLoadRequest> mRequest;
nsCOMPtr<nsISerialEventTarget> mOwningEventTarget;
};
} // namespace mozilla::dom
#endif /* mozilla_dom_workers_WorkerLoadContext_h__ */