summaryrefslogtreecommitdiff
path: root/dom/script/ScriptLoader.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/script/ScriptLoader.cpp')
-rw-r--r--dom/script/ScriptLoader.cpp486
1 files changed, 4 insertions, 482 deletions
diff --git a/dom/script/ScriptLoader.cpp b/dom/script/ScriptLoader.cpp
index b5c8053e88..adc046b7c4 100644
--- a/dom/script/ScriptLoader.cpp
+++ b/dom/script/ScriptLoader.cpp
@@ -4,11 +4,10 @@
* 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/. */
-/*
- * A class that handles loading and evaluation of <script> elements.
- */
-
#include "ScriptLoader.h"
+#include "ScriptLoadHandler.h"
+#include "ModuleLoadRequest.h"
+#include "ModuleScript.h"
#include "prsystem.h"
#include "jsapi.h"
@@ -134,96 +133,6 @@ ScriptLoadRequest::MaybeCancelOffThreadScript()
mOffThreadToken = nullptr;
}
-//////////////////////////////////////////////////////////////
-// ModuleLoadRequest
-//////////////////////////////////////////////////////////////
-
-// A load request for a module, created for every top level module script and
-// every module import. Load request can share a ModuleScript if there are
-// multiple imports of the same module.
-
-class ModuleLoadRequest final : public ScriptLoadRequest
-{
- ~ModuleLoadRequest() {}
-
- ModuleLoadRequest(const ModuleLoadRequest& aOther) = delete;
- ModuleLoadRequest(ModuleLoadRequest&& aOther) = delete;
-
-public:
- NS_DECL_ISUPPORTS_INHERITED
- NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(ModuleLoadRequest, ScriptLoadRequest)
-
- ModuleLoadRequest(nsIScriptElement* aElement,
- uint32_t aVersion,
- CORSMode aCORSMode,
- const SRIMetadata& aIntegrity,
- ScriptLoader* aLoader);
-
- bool IsTopLevel() const {
- return mIsTopLevel;
- }
-
- void SetReady() override;
- void Cancel() override;
-
- void ModuleLoaded();
- void DependenciesLoaded();
- void LoadFailed();
-
- // Is this a request for a top level module script or an import?
- bool mIsTopLevel;
-
- // The base URL used for resolving relative module imports.
- nsCOMPtr<nsIURI> mBaseURL;
-
- // Pointer to the script loader, used to trigger actions when the module load
- // finishes.
- RefPtr<ScriptLoader> mLoader;
-
- // The importing module, or nullptr for top level module scripts. Used to
- // implement the ancestor list checked when fetching module dependencies.
- RefPtr<ModuleLoadRequest> mParent;
-
- // Set to a module script object after a successful load or nullptr on
- // failure.
- RefPtr<ModuleScript> mModuleScript;
-
- // A promise that is completed on successful load of this module and all of
- // its dependencies, indicating that the module is ready for instantiation and
- // evaluation.
- MozPromiseHolder<GenericPromise> mReady;
-
- // Array of imported modules.
- nsTArray<RefPtr<ModuleLoadRequest>> mImports;
-};
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(ModuleLoadRequest)
-NS_INTERFACE_MAP_END_INHERITING(ScriptLoadRequest)
-
-NS_IMPL_CYCLE_COLLECTION_INHERITED(ModuleLoadRequest, ScriptLoadRequest,
- mBaseURL,
- mLoader,
- mParent,
- mModuleScript,
- mImports)
-
-NS_IMPL_ADDREF_INHERITED(ModuleLoadRequest, ScriptLoadRequest)
-NS_IMPL_RELEASE_INHERITED(ModuleLoadRequest, ScriptLoadRequest)
-
-ModuleLoadRequest::ModuleLoadRequest(nsIScriptElement* aElement,
- uint32_t aVersion,
- CORSMode aCORSMode,
- const SRIMetadata &aIntegrity,
- ScriptLoader* aLoader)
- : ScriptLoadRequest(ScriptKind::Module,
- aElement,
- aVersion,
- aCORSMode,
- aIntegrity),
- mIsTopLevel(true),
- mLoader(aLoader)
-{}
-
inline ModuleLoadRequest*
ScriptLoadRequest::AsModuleRequest()
{
@@ -231,194 +140,6 @@ ScriptLoadRequest::AsModuleRequest()
return static_cast<ModuleLoadRequest*>(this);
}
-void ModuleLoadRequest::Cancel()
-{
- ScriptLoadRequest::Cancel();
- mModuleScript = nullptr;
- mProgress = ScriptLoadRequest::Progress::Ready;
- for (size_t i = 0; i < mImports.Length(); i++) {
- mImports[i]->Cancel();
- }
- mReady.RejectIfExists(NS_ERROR_FAILURE, __func__);
-}
-
-void
-ModuleLoadRequest::SetReady()
-{
-#ifdef DEBUG
- for (size_t i = 0; i < mImports.Length(); i++) {
- MOZ_ASSERT(mImports[i]->IsReadyToRun());
- }
-#endif
-
- ScriptLoadRequest::SetReady();
- mReady.ResolveIfExists(true, __func__);
-}
-
-void
-ModuleLoadRequest::ModuleLoaded()
-{
- // A module that was found to be marked as fetching in the module map has now
- // been loaded.
-
- mModuleScript = mLoader->GetFetchedModule(mURI);
- mLoader->StartFetchingModuleDependencies(this);
-}
-
-void
-ModuleLoadRequest::DependenciesLoaded()
-{
- // The module and all of its dependencies have been successfully fetched and
- // compiled.
-
- if (!mLoader->InstantiateModuleTree(this)) {
- LoadFailed();
- return;
- }
-
- SetReady();
- mLoader->ProcessLoadedModuleTree(this);
- mLoader = nullptr;
- mParent = nullptr;
-}
-
-void
-ModuleLoadRequest::LoadFailed()
-{
- Cancel();
- mLoader->ProcessLoadedModuleTree(this);
- mLoader = nullptr;
- mParent = nullptr;
-}
-
-//////////////////////////////////////////////////////////////
-// ModuleScript
-//////////////////////////////////////////////////////////////
-
-// A single module script. May be used to satisfy multiple load requests.
-
-class ModuleScript final : public nsISupports
-{
- enum InstantiationState {
- Uninstantiated,
- Instantiated,
- Errored
- };
-
- RefPtr<ScriptLoader> mLoader;
- nsCOMPtr<nsIURI> mBaseURL;
- JS::Heap<JSObject*> mModuleRecord;
- JS::Heap<JS::Value> mException;
- InstantiationState mInstantiationState;
-
- ~ModuleScript();
-
-public:
- NS_DECL_CYCLE_COLLECTING_ISUPPORTS
- NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ModuleScript)
-
- ModuleScript(ScriptLoader* aLoader,
- nsIURI* aBaseURL,
- JS::Handle<JSObject*> aModuleRecord);
-
- ScriptLoader* Loader() const { return mLoader; }
- JSObject* ModuleRecord() const { return mModuleRecord; }
- JS::Value Exception() const { return mException; }
- nsIURI* BaseURL() const { return mBaseURL; }
-
- void SetInstantiationResult(JS::Handle<JS::Value> aMaybeException);
- bool IsUninstantiated() const {
- return mInstantiationState == Uninstantiated;
- }
- bool IsInstantiated() const {
- return mInstantiationState == Instantiated;
- }
- bool InstantiationFailed() const {
- return mInstantiationState == Errored;
- }
-
- void UnlinkModuleRecord();
-};
-
-NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ModuleScript)
-NS_INTERFACE_MAP_END
-
-NS_IMPL_CYCLE_COLLECTION_CLASS(ModuleScript)
-
-NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ModuleScript)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mLoader)
- NS_IMPL_CYCLE_COLLECTION_UNLINK(mBaseURL)
- tmp->UnlinkModuleRecord();
-NS_IMPL_CYCLE_COLLECTION_UNLINK_END
-
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ModuleScript)
- NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mLoader)
-NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
-
-NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ModuleScript)
- NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mModuleRecord)
- NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mException)
-NS_IMPL_CYCLE_COLLECTION_TRACE_END
-
-NS_IMPL_CYCLE_COLLECTING_ADDREF(ModuleScript)
-NS_IMPL_CYCLE_COLLECTING_RELEASE(ModuleScript)
-
-ModuleScript::ModuleScript(ScriptLoader *aLoader, nsIURI* aBaseURL,
- JS::Handle<JSObject*> aModuleRecord)
- : mLoader(aLoader),
- mBaseURL(aBaseURL),
- mModuleRecord(aModuleRecord),
- mInstantiationState(Uninstantiated)
-{
- MOZ_ASSERT(mLoader);
- MOZ_ASSERT(mBaseURL);
- MOZ_ASSERT(mModuleRecord);
- MOZ_ASSERT(mException.isUndefined());
-
- // Make module's host defined field point to this module script object.
- // This is cleared in the UnlinkModuleRecord().
- JS::SetModuleHostDefinedField(mModuleRecord, JS::PrivateValue(this));
- HoldJSObjects(this);
-}
-
-void
-ModuleScript::UnlinkModuleRecord()
-{
- // Remove module's back reference to this object request if present.
- if (mModuleRecord) {
- MOZ_ASSERT(JS::GetModuleHostDefinedField(mModuleRecord).toPrivate() ==
- this);
- JS::SetModuleHostDefinedField(mModuleRecord, JS::UndefinedValue());
- }
- mModuleRecord = nullptr;
- mException.setUndefined();
-}
-
-ModuleScript::~ModuleScript()
-{
- if (mModuleRecord) {
- // The object may be destroyed without being unlinked first.
- UnlinkModuleRecord();
- }
- DropJSObjects(this);
-}
-
-void
-ModuleScript::SetInstantiationResult(JS::Handle<JS::Value> aMaybeException)
-{
- MOZ_ASSERT(mInstantiationState == Uninstantiated);
- MOZ_ASSERT(mModuleRecord);
- MOZ_ASSERT(mException.isUndefined());
-
- if (aMaybeException.isUndefined()) {
- mInstantiationState = Instantiated;
- } else {
- mModuleRecord = nullptr;
- mException = aMaybeException;
- mInstantiationState = Errored;
- }
-}
-
//////////////////////////////////////////////////////////////
// ScriptLoadRequestList
@@ -2860,204 +2581,5 @@ ScriptLoader::MaybeRemovedDeferRequests()
return false;
}
-//////////////////////////////////////////////////////////////
-// ScriptLoadHandler
-//////////////////////////////////////////////////////////////
-
-ScriptLoadHandler::ScriptLoadHandler(ScriptLoader *aScriptLoader,
- ScriptLoadRequest *aRequest,
- mozilla::dom::SRICheckDataVerifier *aSRIDataVerifier)
- : mScriptLoader(aScriptLoader),
- mRequest(aRequest),
- mSRIDataVerifier(aSRIDataVerifier),
- mSRIStatus(NS_OK),
- mDecoder(),
- mBuffer()
-{}
-
-ScriptLoadHandler::~ScriptLoadHandler()
-{}
-
-NS_IMPL_ISUPPORTS(ScriptLoadHandler, nsIIncrementalStreamLoaderObserver)
-
-NS_IMETHODIMP
-ScriptLoadHandler::OnIncrementalData(nsIIncrementalStreamLoader* aLoader,
- nsISupports* aContext,
- uint32_t aDataLength,
- const uint8_t* aData,
- uint32_t *aConsumedLength)
-{
- if (mRequest->IsCanceled()) {
- // If request cancelled, ignore any incoming data.
- *aConsumedLength = aDataLength;
- return NS_OK;
- }
-
- if (!EnsureDecoder(aLoader, aData, aDataLength,
- /* aEndOfStream = */ false)) {
- return NS_OK;
- }
-
- // Below we will/shall consume entire data chunk.
- *aConsumedLength = aDataLength;
-
- // Decoder has already been initialized. -- trying to decode all loaded bytes.
- nsresult rv = TryDecodeRawData(aData, aDataLength,
- /* aEndOfStream = */ false);
- NS_ENSURE_SUCCESS(rv, rv);
-
- // If SRI is required for this load, appending new bytes to the hash.
- if (mSRIDataVerifier && NS_SUCCEEDED(mSRIStatus)) {
- mSRIStatus = mSRIDataVerifier->Update(aDataLength, aData);
- }
-
- return rv;
-}
-
-nsresult
-ScriptLoadHandler::TryDecodeRawData(const uint8_t* aData,
- uint32_t aDataLength,
- bool aEndOfStream)
-{
- int32_t srcLen = aDataLength;
- const char* src = reinterpret_cast<const char *>(aData);
- int32_t dstLen;
- nsresult rv =
- mDecoder->GetMaxLength(src, srcLen, &dstLen);
-
- NS_ENSURE_SUCCESS(rv, rv);
-
- uint32_t haveRead = mBuffer.length();
-
- CheckedInt<uint32_t> capacity = haveRead;
- capacity += dstLen;
-
- if (!capacity.isValid() || !mBuffer.reserve(capacity.value())) {
- return NS_ERROR_OUT_OF_MEMORY;
- }
-
- rv = mDecoder->Convert(src,
- &srcLen,
- mBuffer.begin() + haveRead,
- &dstLen);
-
- NS_ENSURE_SUCCESS(rv, rv);
-
- haveRead += dstLen;
- MOZ_ASSERT(haveRead <= capacity.value(), "mDecoder produced more data than expected");
- MOZ_ALWAYS_TRUE(mBuffer.resizeUninitialized(haveRead));
-
- return NS_OK;
-}
-
-bool
-ScriptLoadHandler::EnsureDecoder(nsIIncrementalStreamLoader *aLoader,
- const uint8_t* aData,
- uint32_t aDataLength,
- bool aEndOfStream)
-{
- // Check if decoder has already been created.
- if (mDecoder) {
- return true;
- }
-
- nsAutoCString charset;
-
- // JavaScript modules are always UTF-8.
- if (mRequest->IsModuleRequest()) {
- charset = "UTF-8";
- mDecoder = EncodingUtils::DecoderForEncoding(charset);
- return true;
- }
-
- // Determine if BOM check should be done. This occurs either
- // if end-of-stream has been reached, or at least 3 bytes have
- // been read from input.
- if (!aEndOfStream && (aDataLength < 3)) {
- return false;
- }
-
- // Do BOM detection.
- if (nsContentUtils::CheckForBOM(aData, aDataLength, charset)) {
- mDecoder = EncodingUtils::DecoderForEncoding(charset);
- return true;
- }
-
- // BOM detection failed, check content stream for charset.
- nsCOMPtr<nsIRequest> req;
- nsresult rv = aLoader->GetRequest(getter_AddRefs(req));
- NS_ASSERTION(req, "StreamLoader's request went away prematurely");
- NS_ENSURE_SUCCESS(rv, false);
-
- nsCOMPtr<nsIChannel> channel = do_QueryInterface(req);
-
- if (channel &&
- NS_SUCCEEDED(channel->GetContentCharset(charset)) &&
- EncodingUtils::FindEncodingForLabel(charset, charset)) {
- mDecoder = EncodingUtils::DecoderForEncoding(charset);
- return true;
- }
-
- // Check the hint charset from the script element or preload
- // request.
- nsAutoString hintCharset;
- if (!mRequest->IsPreload()) {
- mRequest->mElement->GetScriptCharset(hintCharset);
- } else {
- nsTArray<ScriptLoader::PreloadInfo>::index_type i =
- mScriptLoader->mPreloads.IndexOf(mRequest, 0,
- ScriptLoader::PreloadRequestComparator());
-
- NS_ASSERTION(i != mScriptLoader->mPreloads.NoIndex,
- "Incorrect preload bookkeeping");
- hintCharset = mScriptLoader->mPreloads[i].mCharset;
- }
-
- if (EncodingUtils::FindEncodingForLabel(hintCharset, charset)) {
- mDecoder = EncodingUtils::DecoderForEncoding(charset);
- return true;
- }
-
- // Get the charset from the charset of the document.
- if (mScriptLoader->mDocument) {
- charset = mScriptLoader->mDocument->GetDocumentCharacterSet();
- mDecoder = EncodingUtils::DecoderForEncoding(charset);
- return true;
- }
-
- // Curiously, there are various callers that don't pass aDocument. The
- // fallback in the old code was ISO-8859-1, which behaved like
- // windows-1252. Saying windows-1252 for clarity and for compliance
- // with the Encoding Standard.
- charset = "windows-1252";
- mDecoder = EncodingUtils::DecoderForEncoding(charset);
- return true;
-}
-
-NS_IMETHODIMP
-ScriptLoadHandler::OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
- nsISupports* aContext,
- nsresult aStatus,
- uint32_t aDataLength,
- const uint8_t* aData)
-{
- if (!mRequest->IsCanceled()) {
- DebugOnly<bool> encoderSet =
- EnsureDecoder(aLoader, aData, aDataLength, /* aEndOfStream = */ true);
- MOZ_ASSERT(encoderSet);
- DebugOnly<nsresult> rv = TryDecodeRawData(aData, aDataLength,
- /* aEndOfStream = */ true);
-
- // If SRI is required for this load, appending new bytes to the hash.
- if (mSRIDataVerifier && NS_SUCCEEDED(mSRIStatus)) {
- mSRIStatus = mSRIDataVerifier->Update(aDataLength, aData);
- }
- }
-
- // we have to mediate and use mRequest.
- return mScriptLoader->OnStreamComplete(aLoader, mRequest, aStatus, mSRIStatus,
- mBuffer, mSRIDataVerifier);
-}
-
} // dom namespace
-} // mozilla namespace \ No newline at end of file
+} // mozilla namespace