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/. */
7 #include "ScriptLoadRequest.h"
8 #include "GeckoProfiler.h"
10 #include "mozilla/dom/Document.h"
11 #include "mozilla/dom/ScriptLoadContext.h"
12 #include "mozilla/dom/WorkerLoadContext.h"
13 #include "mozilla/dom/ScriptSettings.h"
14 #include "mozilla/HoldDropJSObjects.h"
15 #include "mozilla/StaticPrefs_dom.h"
16 #include "mozilla/Unused.h"
17 #include "mozilla/Utf8.h" // mozilla::Utf8Unit
19 #include "js/OffThreadScriptCompilation.h"
20 #include "js/SourceText.h"
22 #include "ModuleLoadRequest.h"
23 #include "nsContentUtils.h"
24 #include "nsICacheInfoChannel.h"
25 #include "nsIClassOfService.h"
26 #include "nsISupportsPriority.h"
30 namespace JS::loader
{
32 //////////////////////////////////////////////////////////////
34 //////////////////////////////////////////////////////////////
36 NS_IMPL_CYCLE_COLLECTION(ScriptFetchOptions
, mTriggeringPrincipal
, mElement
)
38 ScriptFetchOptions::ScriptFetchOptions(
39 mozilla::CORSMode aCORSMode
, mozilla::dom::ReferrerPolicy aReferrerPolicy
,
40 const nsAString
& aNonce
, const ParserMetadata aParserMetadata
,
41 nsIPrincipal
* aTriggeringPrincipal
, mozilla::dom::Element
* aElement
)
42 : mCORSMode(aCORSMode
),
43 mReferrerPolicy(aReferrerPolicy
),
45 mParserMetadata(aParserMetadata
),
46 mTriggeringPrincipal(aTriggeringPrincipal
),
49 ScriptFetchOptions::~ScriptFetchOptions() = default;
51 //////////////////////////////////////////////////////////////
53 //////////////////////////////////////////////////////////////
55 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(ScriptLoadRequest
)
56 NS_INTERFACE_MAP_ENTRY(nsISupports
)
59 NS_IMPL_CYCLE_COLLECTING_ADDREF(ScriptLoadRequest
)
60 NS_IMPL_CYCLE_COLLECTING_RELEASE(ScriptLoadRequest
)
62 NS_IMPL_CYCLE_COLLECTION_CLASS(ScriptLoadRequest
)
64 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(ScriptLoadRequest
)
65 NS_IMPL_CYCLE_COLLECTION_UNLINK(mFetchOptions
, mCacheInfo
, mLoadContext
)
66 tmp
->mScriptForBytecodeEncoding
= nullptr;
67 tmp
->DropBytecodeCacheReferences();
68 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
70 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(ScriptLoadRequest
)
71 NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFetchOptions
, mCacheInfo
, mLoadContext
)
72 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
74 NS_IMPL_CYCLE_COLLECTION_TRACE_BEGIN(ScriptLoadRequest
)
75 NS_IMPL_CYCLE_COLLECTION_TRACE_JS_MEMBER_CALLBACK(mScriptForBytecodeEncoding
)
76 NS_IMPL_CYCLE_COLLECTION_TRACE_END
78 ScriptLoadRequest::ScriptLoadRequest(ScriptKind aKind
, nsIURI
* aURI
,
79 ScriptFetchOptions
* aFetchOptions
,
80 const SRIMetadata
& aIntegrity
,
82 LoadContextBase
* aContext
)
84 mState(State::Fetching
),
85 mFetchSourceOnly(false),
86 mDataType(DataType::eUnknown
),
87 mFetchOptions(aFetchOptions
),
88 mIntegrity(aIntegrity
),
94 mLoadContext(aContext
),
95 mEarlyHintPreloaderId(0) {
96 MOZ_ASSERT(mFetchOptions
);
98 mLoadContext
->SetRequest(this);
102 ScriptLoadRequest::~ScriptLoadRequest() { DropJSObjects(this); }
104 void ScriptLoadRequest::SetReady() {
105 MOZ_ASSERT(!IsFinished());
106 mState
= State::Ready
;
109 void ScriptLoadRequest::Cancel() {
110 mState
= State::Canceled
;
111 if (HasScriptLoadContext()) {
112 GetScriptLoadContext()->MaybeCancelOffThreadScript();
116 void ScriptLoadRequest::DropBytecodeCacheReferences() {
117 mCacheInfo
= nullptr;
121 bool ScriptLoadRequest::HasScriptLoadContext() const {
122 return HasLoadContext() && mLoadContext
->IsWindowContext();
125 bool ScriptLoadRequest::HasWorkerLoadContext() const {
126 return HasLoadContext() && mLoadContext
->IsWorkerContext();
129 mozilla::dom::ScriptLoadContext
* ScriptLoadRequest::GetScriptLoadContext() {
130 MOZ_ASSERT(mLoadContext
);
131 return mLoadContext
->AsWindowContext();
134 mozilla::loader::ComponentLoadContext
*
135 ScriptLoadRequest::GetComponentLoadContext() {
136 MOZ_ASSERT(mLoadContext
);
137 return mLoadContext
->AsComponentContext();
140 mozilla::dom::WorkerLoadContext
* ScriptLoadRequest::GetWorkerLoadContext() {
141 MOZ_ASSERT(mLoadContext
);
142 return mLoadContext
->AsWorkerContext();
145 mozilla::dom::WorkletLoadContext
* ScriptLoadRequest::GetWorkletLoadContext() {
146 MOZ_ASSERT(mLoadContext
);
147 return mLoadContext
->AsWorkletContext();
150 ModuleLoadRequest
* ScriptLoadRequest::AsModuleRequest() {
151 MOZ_ASSERT(IsModuleRequest());
152 return static_cast<ModuleLoadRequest
*>(this);
155 const ModuleLoadRequest
* ScriptLoadRequest::AsModuleRequest() const {
156 MOZ_ASSERT(IsModuleRequest());
157 return static_cast<const ModuleLoadRequest
*>(this);
160 void ScriptLoadRequest::SetBytecode() {
161 MOZ_ASSERT(IsUnknownDataType());
162 mDataType
= DataType::eBytecode
;
165 bool ScriptLoadRequest::IsUTF8ParsingEnabled() {
166 if (HasLoadContext()) {
167 if (mLoadContext
->IsWindowContext()) {
168 return mozilla::StaticPrefs::
169 dom_script_loader_external_scripts_utf8_parsing_enabled();
171 if (mLoadContext
->IsWorkerContext()) {
172 return mozilla::StaticPrefs::
173 dom_worker_script_loader_utf8_parsing_enabled();
179 void ScriptLoadRequest::ClearScriptSource() {
180 if (IsTextSource()) {
185 void ScriptLoadRequest::MarkForBytecodeEncoding(JSScript
* aScript
) {
186 MOZ_ASSERT(!IsModuleRequest());
187 MOZ_ASSERT(!IsMarkedForBytecodeEncoding());
188 mScriptForBytecodeEncoding
= aScript
;
192 bool ScriptLoadRequest::IsMarkedForBytecodeEncoding() const {
193 if (IsModuleRequest()) {
194 return AsModuleRequest()->IsModuleMarkedForBytecodeEncoding();
197 return !!mScriptForBytecodeEncoding
;
200 nsresult
ScriptLoadRequest::GetScriptSource(JSContext
* aCx
,
201 MaybeSourceText
* aMaybeSource
) {
202 // If there's no script text, we try to get it from the element
203 if (HasScriptLoadContext() && GetScriptLoadContext()->mIsInline
) {
204 nsAutoString inlineData
;
205 GetScriptLoadContext()->GetScriptElement()->GetScriptText(inlineData
);
207 size_t nbytes
= inlineData
.Length() * sizeof(char16_t
);
208 JS::UniqueTwoByteChars
chars(
209 static_cast<char16_t
*>(JS_malloc(aCx
, nbytes
)));
211 return NS_ERROR_OUT_OF_MEMORY
;
214 memcpy(chars
.get(), inlineData
.get(), nbytes
);
216 SourceText
<char16_t
> srcBuf
;
217 if (!srcBuf
.init(aCx
, std::move(chars
), inlineData
.Length())) {
218 return NS_ERROR_OUT_OF_MEMORY
;
221 aMaybeSource
->construct
<SourceText
<char16_t
>>(std::move(srcBuf
));
225 size_t length
= ScriptTextLength();
227 JS::UniqueTwoByteChars chars
;
228 chars
.reset(ScriptText
<char16_t
>().extractOrCopyRawBuffer());
230 JS_ReportOutOfMemory(aCx
);
231 return NS_ERROR_OUT_OF_MEMORY
;
234 SourceText
<char16_t
> srcBuf
;
235 if (!srcBuf
.init(aCx
, std::move(chars
), length
)) {
236 return NS_ERROR_OUT_OF_MEMORY
;
239 aMaybeSource
->construct
<SourceText
<char16_t
>>(std::move(srcBuf
));
243 MOZ_ASSERT(IsUTF8Text());
244 UniquePtr
<Utf8Unit
[], JS::FreePolicy
> chars
;
245 chars
.reset(ScriptText
<Utf8Unit
>().extractOrCopyRawBuffer());
247 JS_ReportOutOfMemory(aCx
);
248 return NS_ERROR_OUT_OF_MEMORY
;
251 SourceText
<Utf8Unit
> srcBuf
;
252 if (!srcBuf
.init(aCx
, std::move(chars
), length
)) {
253 return NS_ERROR_OUT_OF_MEMORY
;
256 aMaybeSource
->construct
<SourceText
<Utf8Unit
>>(std::move(srcBuf
));
260 //////////////////////////////////////////////////////////////
261 // ScriptLoadRequestList
262 //////////////////////////////////////////////////////////////
264 ScriptLoadRequestList::~ScriptLoadRequestList() { CancelRequestsAndClear(); }
266 void ScriptLoadRequestList::CancelRequestsAndClear() {
268 RefPtr
<ScriptLoadRequest
> first
= StealFirst();
270 // And just let it go out of scope and die.
275 bool ScriptLoadRequestList::Contains(ScriptLoadRequest
* aElem
) const {
276 for (const ScriptLoadRequest
* req
= getFirst(); req
; req
= req
->getNext()) {
286 } // namespace JS::loader