1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Dirk Mueller (mueller@kde.org)
5 * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights
6 * reserved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
18 * You should have received a copy of the GNU Library General Public License
19 * along with this library; see the file COPYING.LIB. If not, write to
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23
24 #include "third_party/blink/renderer/core/html/html_script_element.h"
25
26 #include "third_party/blink/public/mojom/script/script_type.mojom-blink.h"
27 #include "third_party/blink/renderer/bindings/core/v8/html_script_element_or_svg_script_element.h"
28 #include "third_party/blink/renderer/bindings/core/v8/script_event_listener.h"
29 #include "third_party/blink/renderer/bindings/core/v8/string_or_trusted_script.h"
30 #include "third_party/blink/renderer/core/dom/attribute.h"
31 #include "third_party/blink/renderer/core/dom/document.h"
32 #include "third_party/blink/renderer/core/dom/events/event.h"
33 #include "third_party/blink/renderer/core/dom/text.h"
34 #include "third_party/blink/renderer/core/frame/csp/content_security_policy.h"
35 #include "third_party/blink/renderer/core/html_names.h"
36 #include "third_party/blink/renderer/core/script/script_loader.h"
37 #include "third_party/blink/renderer/core/script/script_runner.h"
38 #include "third_party/blink/renderer/core/trustedtypes/trusted_script.h"
39 #include "third_party/blink/renderer/core/trustedtypes/trusted_types_util.h"
40 #include "third_party/blink/renderer/platform/bindings/exception_state.h"
41 #include "third_party/blink/renderer/platform/instrumentation/use_counter.h"
42 #include "third_party/blink/renderer/platform/runtime_enabled_features.h"
43
44 namespace blink {
45
HTMLScriptElement(Document & document,const CreateElementFlags flags)46 HTMLScriptElement::HTMLScriptElement(Document& document,
47 const CreateElementFlags flags)
48 : HTMLElement(html_names::kScriptTag, document),
49 children_changed_by_api_(false),
50 loader_(InitializeScriptLoader(flags.IsCreatedByParser(),
51 flags.WasAlreadyStarted())) {}
52
GetCheckedAttributeTypes() const53 const AttrNameToTrustedType& HTMLScriptElement::GetCheckedAttributeTypes()
54 const {
55 DEFINE_STATIC_LOCAL(AttrNameToTrustedType, attribute_map,
56 ({{"src", SpecificTrustedType::kScriptURL}}));
57 return attribute_map;
58 }
59
IsURLAttribute(const Attribute & attribute) const60 bool HTMLScriptElement::IsURLAttribute(const Attribute& attribute) const {
61 return attribute.GetName() == html_names::kSrcAttr ||
62 HTMLElement::IsURLAttribute(attribute);
63 }
64
HasLegalLinkAttribute(const QualifiedName & name) const65 bool HTMLScriptElement::HasLegalLinkAttribute(const QualifiedName& name) const {
66 return name == html_names::kSrcAttr ||
67 HTMLElement::HasLegalLinkAttribute(name);
68 }
69
SubResourceAttributeName() const70 const QualifiedName& HTMLScriptElement::SubResourceAttributeName() const {
71 return html_names::kSrcAttr;
72 }
73
ChildrenChanged(const ChildrenChange & change)74 void HTMLScriptElement::ChildrenChanged(const ChildrenChange& change) {
75 HTMLElement::ChildrenChanged(change);
76 if (change.IsChildInsertion())
77 loader_->ChildrenChanged();
78
79 // We'll record whether the script element children were ever changed by
80 // the API (as opposed to the parser).
81 children_changed_by_api_ |= !change.ByParser();
82 }
83
DidMoveToNewDocument(Document & old_document)84 void HTMLScriptElement::DidMoveToNewDocument(Document& old_document) {
85 ScriptRunner::MovePendingScript(old_document, GetDocument(), loader_.Get());
86 HTMLElement::DidMoveToNewDocument(old_document);
87 }
88
ParseAttribute(const AttributeModificationParams & params)89 void HTMLScriptElement::ParseAttribute(
90 const AttributeModificationParams& params) {
91 if (params.name == html_names::kSrcAttr) {
92 loader_->HandleSourceAttribute(params.new_value);
93 LogUpdateAttributeIfIsolatedWorldAndInDocument("script", params);
94 } else if (params.name == html_names::kAsyncAttr) {
95 loader_->HandleAsyncAttribute();
96 } else if (params.name == html_names::kImportanceAttr &&
97 RuntimeEnabledFeatures::PriorityHintsEnabled(&GetDocument())) {
98 // The only thing we need to do for the the importance attribute/Priority
99 // Hints is count usage upon parsing. Processing the value happens when the
100 // element loads.
101 UseCounter::Count(GetDocument(), WebFeature::kPriorityHints);
102 } else {
103 HTMLElement::ParseAttribute(params);
104 }
105 }
106
InsertedInto(ContainerNode & insertion_point)107 Node::InsertionNotificationRequest HTMLScriptElement::InsertedInto(
108 ContainerNode& insertion_point) {
109 if (insertion_point.isConnected() && HasSourceAttribute() &&
110 !ScriptLoader::IsValidScriptTypeAndLanguage(
111 TypeAttributeValue(), LanguageAttributeValue(),
112 ScriptLoader::kDisallowLegacyTypeInTypeAttribute)) {
113 UseCounter::Count(GetDocument(),
114 WebFeature::kScriptElementWithInvalidTypeHasSrc);
115 }
116 HTMLElement::InsertedInto(insertion_point);
117 LogAddElementIfIsolatedWorldAndInDocument("script", html_names::kSrcAttr);
118
119 return kInsertionShouldCallDidNotifySubtreeInsertions;
120 }
121
DidNotifySubtreeInsertionsToDocument()122 void HTMLScriptElement::DidNotifySubtreeInsertionsToDocument() {
123 loader_->DidNotifySubtreeInsertionsToDocument();
124 }
125
setText(const String & string)126 void HTMLScriptElement::setText(const String& string) {
127 setTextContent(string);
128 }
129
text(StringOrTrustedScript & result)130 void HTMLScriptElement::text(StringOrTrustedScript& result) {
131 result.SetString(TextFromChildren());
132 }
133
setInnerText(const StringOrTrustedScript & string_or_trusted_script,ExceptionState & exception_state)134 void HTMLScriptElement::setInnerText(
135 const StringOrTrustedScript& string_or_trusted_script,
136 ExceptionState& exception_state) {
137 String value = TrustedTypesCheckForScript(
138 string_or_trusted_script, GetExecutionContext(), exception_state);
139 if (!exception_state.HadException()) {
140 // https://w3c.github.io/webappsec-trusted-types/dist/spec/#setting-slot-values
141 // On setting, the innerText [...] perform the regular steps, and then set
142 // content object's [[ScriptText]] internal slot value [...].
143 HTMLElement::setInnerText(value, exception_state);
144 script_text_internal_slot_ = ParkableString(value.Impl());
145 }
146 }
147
setTextContent(const String & string)148 void HTMLScriptElement::setTextContent(const String& string) {
149 // https://w3c.github.io/webappsec-trusted-types/dist/spec/#setting-slot-values
150 // On setting, [..] textContent [..] perform the regular steps, and then set
151 // content object's [[ScriptText]] internal slot value [...].
152 Node::setTextContent(string);
153 script_text_internal_slot_ = ParkableString(string.Impl());
154 }
155
setTextContent(const StringOrTrustedScript & string_or_trusted_script,ExceptionState & exception_state)156 void HTMLScriptElement::setTextContent(
157 const StringOrTrustedScript& string_or_trusted_script,
158 ExceptionState& exception_state) {
159 String value = TrustedTypesCheckForScript(
160 string_or_trusted_script, GetExecutionContext(), exception_state);
161 if (!exception_state.HadException()) {
162 // https://w3c.github.io/webappsec-trusted-types/dist/spec/#setting-slot-values
163 // On setting, [..] textContent [..] perform the regular steps, and then set
164 // content object's [[ScriptText]] internal slot value [...].
165 Node::setTextContent(value);
166 script_text_internal_slot_ = ParkableString(value.Impl());
167 }
168 }
169
setAsync(bool async)170 void HTMLScriptElement::setAsync(bool async) {
171 SetBooleanAttribute(html_names::kAsyncAttr, async);
172 loader_->HandleAsyncAttribute();
173 }
174
FinishParsingChildren()175 void HTMLScriptElement::FinishParsingChildren() {
176 Element::FinishParsingChildren();
177
178 // We normally expect the parser to finish parsing before any script gets
179 // a chance to manipulate the script. However, if script parsing gets
180 // deferrred (or similar; see crbug.com/1033101) then a script might get
181 // access to the HTMLScriptElement before. In this case, we cannot blindly
182 // accept the current TextFromChildren as a parser result.
183 DCHECK(children_changed_by_api_ || !script_text_internal_slot_.length());
184 if (!children_changed_by_api_)
185 script_text_internal_slot_ = ParkableString(TextFromChildren().Impl());
186 }
187
async() const188 bool HTMLScriptElement::async() const {
189 return FastHasAttribute(html_names::kAsyncAttr) || loader_->IsNonBlocking();
190 }
191
SourceAttributeValue() const192 String HTMLScriptElement::SourceAttributeValue() const {
193 return FastGetAttribute(html_names::kSrcAttr).GetString();
194 }
195
CharsetAttributeValue() const196 String HTMLScriptElement::CharsetAttributeValue() const {
197 return FastGetAttribute(html_names::kCharsetAttr).GetString();
198 }
199
TypeAttributeValue() const200 String HTMLScriptElement::TypeAttributeValue() const {
201 return FastGetAttribute(html_names::kTypeAttr).GetString();
202 }
203
LanguageAttributeValue() const204 String HTMLScriptElement::LanguageAttributeValue() const {
205 return FastGetAttribute(html_names::kLanguageAttr).GetString();
206 }
207
NomoduleAttributeValue() const208 bool HTMLScriptElement::NomoduleAttributeValue() const {
209 return FastHasAttribute(html_names::kNomoduleAttr);
210 }
211
ForAttributeValue() const212 String HTMLScriptElement::ForAttributeValue() const {
213 return FastGetAttribute(html_names::kForAttr).GetString();
214 }
215
EventAttributeValue() const216 String HTMLScriptElement::EventAttributeValue() const {
217 return FastGetAttribute(html_names::kEventAttr).GetString();
218 }
219
CrossOriginAttributeValue() const220 String HTMLScriptElement::CrossOriginAttributeValue() const {
221 return FastGetAttribute(html_names::kCrossoriginAttr);
222 }
223
IntegrityAttributeValue() const224 String HTMLScriptElement::IntegrityAttributeValue() const {
225 return FastGetAttribute(html_names::kIntegrityAttr);
226 }
227
ReferrerPolicyAttributeValue() const228 String HTMLScriptElement::ReferrerPolicyAttributeValue() const {
229 return FastGetAttribute(html_names::kReferrerpolicyAttr);
230 }
231
ImportanceAttributeValue() const232 String HTMLScriptElement::ImportanceAttributeValue() const {
233 return FastGetAttribute(html_names::kImportanceAttr);
234 }
235
ChildTextContent()236 String HTMLScriptElement::ChildTextContent() {
237 return TextFromChildren();
238 }
239
ScriptTextInternalSlot() const240 String HTMLScriptElement::ScriptTextInternalSlot() const {
241 return script_text_internal_slot_.ToString();
242 }
243
AsyncAttributeValue() const244 bool HTMLScriptElement::AsyncAttributeValue() const {
245 return FastHasAttribute(html_names::kAsyncAttr);
246 }
247
DeferAttributeValue() const248 bool HTMLScriptElement::DeferAttributeValue() const {
249 return FastHasAttribute(html_names::kDeferAttr);
250 }
251
HasSourceAttribute() const252 bool HTMLScriptElement::HasSourceAttribute() const {
253 return FastHasAttribute(html_names::kSrcAttr);
254 }
255
IsConnected() const256 bool HTMLScriptElement::IsConnected() const {
257 return Node::isConnected();
258 }
259
HasChildren() const260 bool HTMLScriptElement::HasChildren() const {
261 return Node::hasChildren();
262 }
263
GetNonceForElement() const264 const AtomicString& HTMLScriptElement::GetNonceForElement() const {
265 return ContentSecurityPolicy::IsNonceableElement(this) ? nonce()
266 : g_null_atom;
267 }
268
AllowInlineScriptForCSP(const AtomicString & nonce,const WTF::OrdinalNumber & context_line,const String & script_content)269 bool HTMLScriptElement::AllowInlineScriptForCSP(
270 const AtomicString& nonce,
271 const WTF::OrdinalNumber& context_line,
272 const String& script_content) {
273 return GetDocument().GetContentSecurityPolicyForWorld()->AllowInline(
274 ContentSecurityPolicy::InlineType::kScript, this, script_content, nonce,
275 GetDocument().Url(), context_line);
276 }
277
GetDocument() const278 Document& HTMLScriptElement::GetDocument() const {
279 return Node::GetDocument();
280 }
281
DispatchLoadEvent()282 void HTMLScriptElement::DispatchLoadEvent() {
283 DispatchEvent(*Event::Create(event_type_names::kLoad));
284 }
285
DispatchErrorEvent()286 void HTMLScriptElement::DispatchErrorEvent() {
287 DispatchEvent(*Event::Create(event_type_names::kError));
288 }
289
SetScriptElementForBinding(HTMLScriptElementOrSVGScriptElement & element)290 void HTMLScriptElement::SetScriptElementForBinding(
291 HTMLScriptElementOrSVGScriptElement& element) {
292 if (!IsInV1ShadowTree())
293 element.SetHTMLScriptElement(this);
294 }
295
GetScriptElementType()296 ScriptElementBase::Type HTMLScriptElement::GetScriptElementType() {
297 return ScriptElementBase::Type::kHTMLScriptElement;
298 }
299
CloneWithoutAttributesAndChildren(Document & factory) const300 Element& HTMLScriptElement::CloneWithoutAttributesAndChildren(
301 Document& factory) const {
302 CreateElementFlags flags =
303 CreateElementFlags::ByCloneNode().SetAlreadyStarted(
304 loader_->AlreadyStarted());
305 return *factory.CreateElement(TagQName(), flags, IsValue());
306 }
307
Trace(Visitor * visitor)308 void HTMLScriptElement::Trace(Visitor* visitor) {
309 visitor->Trace(loader_);
310 HTMLElement::Trace(visitor);
311 ScriptElementBase::Trace(visitor);
312 }
313
314 } // namespace blink
315