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