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/. */
6
7 #include "nsGkAtoms.h"
8 #include "nsStyleConsts.h"
9 #include "mozilla/dom/Document.h"
10 #include "nsNetUtil.h"
11 #include "nsContentUtils.h"
12 #include "nsUnicharUtils.h" // for nsCaseInsensitiveStringComparator()
13 #include "nsIScriptContext.h"
14 #include "nsIScriptGlobalObject.h"
15 #include "nsServiceManagerUtils.h"
16 #include "nsError.h"
17 #include "nsTArray.h"
18 #include "nsDOMJSUtils.h"
19 #include "nsIScriptError.h"
20 #include "nsISupportsImpl.h"
21 #include "mozilla/dom/HTMLScriptElement.h"
22 #include "mozilla/dom/HTMLScriptElementBinding.h"
23
24 NS_IMPL_NS_NEW_HTML_ELEMENT_CHECK_PARSER(Script)
25
26 namespace mozilla::dom {
27
WrapNode(JSContext * aCx,JS::Handle<JSObject * > aGivenProto)28 JSObject* HTMLScriptElement::WrapNode(JSContext* aCx,
29 JS::Handle<JSObject*> aGivenProto) {
30 return HTMLScriptElement_Binding::Wrap(aCx, this, aGivenProto);
31 }
32
HTMLScriptElement(already_AddRefed<mozilla::dom::NodeInfo> && aNodeInfo,FromParser aFromParser)33 HTMLScriptElement::HTMLScriptElement(
34 already_AddRefed<mozilla::dom::NodeInfo>&& aNodeInfo,
35 FromParser aFromParser)
36 : nsGenericHTMLElement(std::move(aNodeInfo)), ScriptElement(aFromParser) {
37 AddMutationObserver(this);
38 }
39
40 HTMLScriptElement::~HTMLScriptElement() = default;
41
NS_IMPL_ISUPPORTS_INHERITED(HTMLScriptElement,nsGenericHTMLElement,nsIScriptLoaderObserver,nsIScriptElement,nsIMutationObserver)42 NS_IMPL_ISUPPORTS_INHERITED(HTMLScriptElement, nsGenericHTMLElement,
43 nsIScriptLoaderObserver, nsIScriptElement,
44 nsIMutationObserver)
45
46 nsresult HTMLScriptElement::BindToTree(BindContext& aContext,
47 nsINode& aParent) {
48 nsresult rv = nsGenericHTMLElement::BindToTree(aContext, aParent);
49 NS_ENSURE_SUCCESS(rv, rv);
50
51 if (IsInComposedDoc()) {
52 MaybeProcessScript();
53 }
54
55 return NS_OK;
56 }
57
ParseAttribute(int32_t aNamespaceID,nsAtom * aAttribute,const nsAString & aValue,nsIPrincipal * aMaybeScriptedPrincipal,nsAttrValue & aResult)58 bool HTMLScriptElement::ParseAttribute(int32_t aNamespaceID, nsAtom* aAttribute,
59 const nsAString& aValue,
60 nsIPrincipal* aMaybeScriptedPrincipal,
61 nsAttrValue& aResult) {
62 if (aNamespaceID == kNameSpaceID_None) {
63 if (aAttribute == nsGkAtoms::crossorigin) {
64 ParseCORSValue(aValue, aResult);
65 return true;
66 }
67
68 if (aAttribute == nsGkAtoms::integrity) {
69 aResult.ParseStringOrAtom(aValue);
70 return true;
71 }
72 }
73
74 return nsGenericHTMLElement::ParseAttribute(aNamespaceID, aAttribute, aValue,
75 aMaybeScriptedPrincipal, aResult);
76 }
77
Clone(dom::NodeInfo * aNodeInfo,nsINode ** aResult) const78 nsresult HTMLScriptElement::Clone(dom::NodeInfo* aNodeInfo,
79 nsINode** aResult) const {
80 *aResult = nullptr;
81
82 HTMLScriptElement* it = new (aNodeInfo->NodeInfoManager())
83 HTMLScriptElement(do_AddRef(aNodeInfo), NOT_FROM_PARSER);
84
85 nsCOMPtr<nsINode> kungFuDeathGrip = it;
86 nsresult rv = const_cast<HTMLScriptElement*>(this)->CopyInnerTo(it);
87 NS_ENSURE_SUCCESS(rv, rv);
88
89 // The clone should be marked evaluated if we are.
90 it->mAlreadyStarted = mAlreadyStarted;
91 it->mLineNumber = mLineNumber;
92 it->mMalformed = mMalformed;
93
94 kungFuDeathGrip.swap(*aResult);
95
96 return NS_OK;
97 }
98
AfterSetAttr(int32_t aNamespaceID,nsAtom * aName,const nsAttrValue * aValue,const nsAttrValue * aOldValue,nsIPrincipal * aMaybeScriptedPrincipal,bool aNotify)99 nsresult HTMLScriptElement::AfterSetAttr(int32_t aNamespaceID, nsAtom* aName,
100 const nsAttrValue* aValue,
101 const nsAttrValue* aOldValue,
102 nsIPrincipal* aMaybeScriptedPrincipal,
103 bool aNotify) {
104 if (nsGkAtoms::async == aName && kNameSpaceID_None == aNamespaceID) {
105 mForceAsync = false;
106 }
107 if (nsGkAtoms::src == aName && kNameSpaceID_None == aNamespaceID) {
108 mSrcTriggeringPrincipal = nsContentUtils::GetAttrTriggeringPrincipal(
109 this, aValue ? aValue->GetStringValue() : EmptyString(),
110 aMaybeScriptedPrincipal);
111 }
112 return nsGenericHTMLElement::AfterSetAttr(
113 aNamespaceID, aName, aValue, aOldValue, aMaybeScriptedPrincipal, aNotify);
114 }
115
GetInnerHTML(nsAString & aInnerHTML,OOMReporter & aError)116 void HTMLScriptElement::GetInnerHTML(nsAString& aInnerHTML,
117 OOMReporter& aError) {
118 if (!nsContentUtils::GetNodeTextContent(this, false, aInnerHTML, fallible)) {
119 aError.ReportOOM();
120 }
121 }
122
SetInnerHTML(const nsAString & aInnerHTML,nsIPrincipal * aScriptedPrincipal,ErrorResult & aError)123 void HTMLScriptElement::SetInnerHTML(const nsAString& aInnerHTML,
124 nsIPrincipal* aScriptedPrincipal,
125 ErrorResult& aError) {
126 aError = nsContentUtils::SetNodeTextContent(this, aInnerHTML, true);
127 }
128
GetText(nsAString & aValue,ErrorResult & aRv)129 void HTMLScriptElement::GetText(nsAString& aValue, ErrorResult& aRv) {
130 if (!nsContentUtils::GetNodeTextContent(this, false, aValue, fallible)) {
131 aRv.Throw(NS_ERROR_OUT_OF_MEMORY);
132 }
133 }
134
SetText(const nsAString & aValue,ErrorResult & aRv)135 void HTMLScriptElement::SetText(const nsAString& aValue, ErrorResult& aRv) {
136 aRv = nsContentUtils::SetNodeTextContent(this, aValue, true);
137 }
138
139 // variation of this code in SVGScriptElement - check if changes
140 // need to be transfered when modifying
141
GetScriptType(nsAString & aType)142 bool HTMLScriptElement::GetScriptType(nsAString& aType) {
143 nsAutoString type;
144 if (!GetAttr(kNameSpaceID_None, nsGkAtoms::type, type)) {
145 return false;
146 }
147
148 // ASCII whitespace https://infra.spec.whatwg.org/#ascii-whitespace:
149 // U+0009 TAB, U+000A LF, U+000C FF, U+000D CR, or U+0020 SPACE.
150 static const char kASCIIWhitespace[] = "\t\n\f\r ";
151 type.Trim(kASCIIWhitespace);
152
153 aType.Assign(type);
154 return true;
155 }
156
GetScriptText(nsAString & text)157 void HTMLScriptElement::GetScriptText(nsAString& text) {
158 GetText(text, IgnoreErrors());
159 }
160
GetScriptCharset(nsAString & charset)161 void HTMLScriptElement::GetScriptCharset(nsAString& charset) {
162 GetCharset(charset);
163 }
164
FreezeExecutionAttrs(Document * aOwnerDoc)165 void HTMLScriptElement::FreezeExecutionAttrs(Document* aOwnerDoc) {
166 if (mFrozen) {
167 return;
168 }
169
170 MOZ_ASSERT(!mIsModule && !mAsync && !mDefer && !mExternal);
171
172 // Determine whether this is a classic script or a module script.
173 nsAutoString type;
174 GetScriptType(type);
175 mIsModule = aOwnerDoc->ModuleScriptsEnabled() && !type.IsEmpty() &&
176 type.LowerCaseEqualsASCII("module");
177
178 // variation of this code in SVGScriptElement - check if changes
179 // need to be transfered when modifying. Note that we don't use GetSrc here
180 // because it will return the base URL when the attr value is "".
181 nsAutoString src;
182 if (GetAttr(kNameSpaceID_None, nsGkAtoms::src, src)) {
183 // Empty src should be treated as invalid URL.
184 if (!src.IsEmpty()) {
185 nsContentUtils::NewURIWithDocumentCharset(getter_AddRefs(mUri), src,
186 OwnerDoc(), GetBaseURI());
187
188 if (!mUri) {
189 AutoTArray<nsString, 2> params = {u"src"_ns, src};
190
191 nsContentUtils::ReportToConsole(
192 nsIScriptError::warningFlag, "HTML"_ns, OwnerDoc(),
193 nsContentUtils::eDOM_PROPERTIES, "ScriptSourceInvalidUri", params,
194 nullptr, u""_ns, GetScriptLineNumber(), GetScriptColumnNumber());
195 }
196 } else {
197 AutoTArray<nsString, 1> params = {u"src"_ns};
198
199 nsContentUtils::ReportToConsole(
200 nsIScriptError::warningFlag, "HTML"_ns, OwnerDoc(),
201 nsContentUtils::eDOM_PROPERTIES, "ScriptSourceEmpty", params, nullptr,
202 u""_ns, GetScriptLineNumber(), GetScriptColumnNumber());
203 }
204
205 // At this point mUri will be null for invalid URLs.
206 mExternal = true;
207 }
208
209 bool async = (mExternal || mIsModule) && Async();
210 bool defer = mExternal && Defer();
211
212 mDefer = !async && defer;
213 mAsync = async;
214
215 mFrozen = true;
216 }
217
GetCORSMode() const218 CORSMode HTMLScriptElement::GetCORSMode() const {
219 return AttrValueToCORSMode(GetParsedAttr(nsGkAtoms::crossorigin));
220 }
221
GetReferrerPolicy()222 mozilla::dom::ReferrerPolicy HTMLScriptElement::GetReferrerPolicy() {
223 return GetReferrerPolicyAsEnum();
224 }
225
HasScriptContent()226 bool HTMLScriptElement::HasScriptContent() {
227 return (mFrozen ? mExternal : HasAttr(kNameSpaceID_None, nsGkAtoms::src)) ||
228 nsContentUtils::HasNonEmptyTextContent(this);
229 }
230
231 } // namespace mozilla::dom
232