diff options
Diffstat (limited to 'js/loader/ScriptLoadRequest.cpp')
-rw-r--r-- | js/loader/ScriptLoadRequest.cpp | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/js/loader/ScriptLoadRequest.cpp b/js/loader/ScriptLoadRequest.cpp new file mode 100644 index 0000000000..fb2c567ad3 --- /dev/null +++ b/js/loader/ScriptLoadRequest.cpp @@ -0,0 +1,241 @@ +/* -*- 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/. */ + +#include "ScriptLoadRequest.h" +#include "GeckoProfiler.h" + +#include "mozilla/dom/Document.h" +#include "mozilla/dom/ScriptLoadContext.h" +#include "mozilla/dom/WorkerLoadContext.h" +#include "mozilla/dom/ScriptSettings.h" +#include "mozilla/HoldDropJSObjects.h" +#include "mozilla/StaticPrefs_dom.h" +#include "mozilla/Unused.h" +#include "mozilla/Utf8.h" // mozilla::Utf8Unit + +#include "js/SourceText.h" + +#include "ModuleLoadRequest.h" +#include "nsContentUtils.h" +#include "nsICacheInfoChannel.h" +#include "nsIClassOfService.h" +#include "nsISupportsPriority.h" + +using JS::SourceText; + +namespace JS::loader { + +////////////////////////////////////////////////////////////// +// ScriptFetchOptions +////////////////////////////////////////////////////////////// + +NS_IMPL_CYCLE_COLLECTION(ScriptFetchOptions, mTriggeringPrincipal, mElement) + +ScriptFetchOptions::ScriptFetchOptions( + mozilla::CORSMode aCORSMode, const nsAString& aNonce, + mozilla::dom::RequestPriority aFetchPriority, + const ParserMetadata aParserMetadata, nsIPrincipal* aTriggeringPrincipal, + mozilla::dom::Element* aElement) + : mCORSMode(aCORSMode), + mNonce(aNonce), + mFetchPriority(aFetchPriority), + mParserMetadata(aParserMetadata), + mTriggeringPrincipal(aTriggeringPrincipal), + mElement(aElement) {} + +ScriptFetchOptions::~ScriptFetchOptions() = default; + +////////////////////////////////////////////////////////////// +// ScriptLoadRequest +////////////////////////////////////////////////////////////// + +NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ScriptLoadRequest) + NS_INTERFACE_MAP_ENTRY(nsISupports) +NS_INTERFACE_MAP_END + +NS_IMPL_CYCLE_COLLECTING_ADDREF(ScriptLoadRequest) +NS_IMPL_CYCLE_COLLECTING_RELEASE(ScriptLoadRequest) + +NS_IMPL_CYCLE_COLLECTION_CLASS(ScriptLoadRequest) + +NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ScriptLoadRequest) + NS_IMPL_CYCLE_COLLECTION_UNLINK(mFetchOptions, mCacheInfo, mLoadContext, + mLoadedScript) + tmp->mScriptForBytecodeEncoding = nullptr; + tmp->DropBytecodeCacheReferences(); +NS_IMPL_CYCLE_COLLECTION_UNLINK_END + +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ScriptLoadRequest) + NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFetchOptions, mCacheInfo, mLoadContext, + mLoadedScript) +NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END + +NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ScriptLoadRequest) + NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mScriptForBytecodeEncoding) +NS_IMPL_CYCLE_COLLECTION_TRACE_END + +ScriptLoadRequest::ScriptLoadRequest( + ScriptKind aKind, nsIURI* aURI, + mozilla::dom::ReferrerPolicy aReferrerPolicy, + ScriptFetchOptions* aFetchOptions, const SRIMetadata& aIntegrity, + nsIURI* aReferrer, LoadContextBase* aContext) + : mKind(aKind), + mState(State::CheckingCache), + mFetchSourceOnly(false), + mReferrerPolicy(aReferrerPolicy), + mFetchOptions(aFetchOptions), + mIntegrity(aIntegrity), + mReferrer(aReferrer), + mURI(aURI), + mLoadContext(aContext), + mEarlyHintPreloaderId(0) { + MOZ_ASSERT(mFetchOptions); + if (mLoadContext) { + mLoadContext->SetRequest(this); + } +} + +ScriptLoadRequest::~ScriptLoadRequest() { DropJSObjects(this); } + +void ScriptLoadRequest::SetReady() { + MOZ_ASSERT(!IsFinished()); + mState = State::Ready; +} + +void ScriptLoadRequest::Cancel() { + mState = State::Canceled; + if (HasScriptLoadContext()) { + GetScriptLoadContext()->MaybeCancelOffThreadScript(); + } +} + +void ScriptLoadRequest::DropBytecodeCacheReferences() { + mCacheInfo = nullptr; + DropJSObjects(this); +} + +bool ScriptLoadRequest::HasScriptLoadContext() const { + return HasLoadContext() && mLoadContext->IsWindowContext(); +} + +bool ScriptLoadRequest::HasWorkerLoadContext() const { + return HasLoadContext() && mLoadContext->IsWorkerContext(); +} + +mozilla::dom::ScriptLoadContext* ScriptLoadRequest::GetScriptLoadContext() { + MOZ_ASSERT(mLoadContext); + return mLoadContext->AsWindowContext(); +} + +mozilla::loader::SyncLoadContext* ScriptLoadRequest::GetSyncLoadContext() { + MOZ_ASSERT(mLoadContext); + return mLoadContext->AsSyncContext(); +} + +mozilla::dom::WorkerLoadContext* ScriptLoadRequest::GetWorkerLoadContext() { + MOZ_ASSERT(mLoadContext); + return mLoadContext->AsWorkerContext(); +} + +mozilla::dom::WorkletLoadContext* ScriptLoadRequest::GetWorkletLoadContext() { + MOZ_ASSERT(mLoadContext); + return mLoadContext->AsWorkletContext(); +} + +ModuleLoadRequest* ScriptLoadRequest::AsModuleRequest() { + MOZ_ASSERT(IsModuleRequest()); + return static_cast<ModuleLoadRequest*>(this); +} + +const ModuleLoadRequest* ScriptLoadRequest::AsModuleRequest() const { + MOZ_ASSERT(IsModuleRequest()); + return static_cast<const ModuleLoadRequest*>(this); +} + +void ScriptLoadRequest::NoCacheEntryFound() { + MOZ_ASSERT(IsCheckingCache()); + MOZ_ASSERT(mURI); + // At the time where we check in the cache, the mBaseURL is not set, as this + // is resolved by the network. Thus we use the mURI, for checking the cache + // and later replace the mBaseURL using what the Channel->GetURI will provide. + switch (mKind) { + case ScriptKind::eClassic: + case ScriptKind::eImportMap: + mLoadedScript = new ClassicScript(mReferrerPolicy, mFetchOptions, mURI); + break; + case ScriptKind::eModule: + mLoadedScript = new ModuleScript(mReferrerPolicy, mFetchOptions, mURI); + break; + case ScriptKind::eEvent: + MOZ_ASSERT_UNREACHABLE("EventScripts are not using ScriptLoadRequest"); + break; + } + mState = State::Fetching; +} + +void ScriptLoadRequest::SetPendingFetchingError() { + MOZ_ASSERT(IsCheckingCache()); + mState = State::PendingFetchingError; +} + +void ScriptLoadRequest::MarkForBytecodeEncoding(JSScript* aScript) { + MOZ_ASSERT(!IsModuleRequest()); + MOZ_ASSERT(!IsMarkedForBytecodeEncoding()); + mScriptForBytecodeEncoding = aScript; + HoldJSObjects(this); +} + +bool ScriptLoadRequest::IsMarkedForBytecodeEncoding() const { + if (IsModuleRequest()) { + return AsModuleRequest()->IsModuleMarkedForBytecodeEncoding(); + } + + return !!mScriptForBytecodeEncoding; +} + +static bool IsInternalURIScheme(nsIURI* uri) { + return uri->SchemeIs("moz-extension") || uri->SchemeIs("resource") || + uri->SchemeIs("chrome"); +} + +void ScriptLoadRequest::SetBaseURLFromChannelAndOriginalURI( + nsIChannel* aChannel, nsIURI* aOriginalURI) { + // Fixup moz-extension: and resource: URIs, because the channel URI will + // point to file:, which won't be allowed to load. + if (aOriginalURI && IsInternalURIScheme(aOriginalURI)) { + mBaseURL = aOriginalURI; + } else { + aChannel->GetURI(getter_AddRefs(mBaseURL)); + } +} + +////////////////////////////////////////////////////////////// +// ScriptLoadRequestList +////////////////////////////////////////////////////////////// + +ScriptLoadRequestList::~ScriptLoadRequestList() { CancelRequestsAndClear(); } + +void ScriptLoadRequestList::CancelRequestsAndClear() { + while (!isEmpty()) { + RefPtr<ScriptLoadRequest> first = StealFirst(); + first->Cancel(); + // And just let it go out of scope and die. + } +} + +#ifdef DEBUG +bool ScriptLoadRequestList::Contains(ScriptLoadRequest* aElem) const { + for (const ScriptLoadRequest* req = getFirst(); req; req = req->getNext()) { + if (req == aElem) { + return true; + } + } + + return false; +} +#endif // DEBUG + +} // namespace JS::loader |