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