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 #ifndef nsIScriptElement_h___
8 #define nsIScriptElement_h___
9 
10 #include "mozilla/AlreadyAddRefed.h"
11 #include "mozilla/Assertions.h"
12 #include "mozilla/CORSMode.h"
13 #include "mozilla/dom/FromParser.h"
14 #include "nsCOMPtr.h"
15 #include "nsID.h"
16 #include "nsIScriptLoaderObserver.h"
17 #include "nsIWeakReferenceUtils.h"
18 #include "nsStringFwd.h"
19 #include "nscore.h"
20 
21 // XXX Avoid including this here by moving function bodies to the cpp file
22 #include "nsIPrincipal.h"
23 
24 class nsIParser;
25 class nsIPrincipal;
26 class nsIURI;
27 
28 namespace mozilla::dom {
29 class Document;
30 enum class ReferrerPolicy : uint8_t;
31 }  // namespace mozilla::dom
32 
33 // Must be kept in sync with xpcom/rust/xpcom/src/interfaces/nonidl.rs
34 #define NS_ISCRIPTELEMENT_IID                        \
35   {                                                  \
36     0xe60fca9b, 0x1b96, 0x4e4e, {                    \
37       0xa9, 0xb4, 0xdc, 0x98, 0x4f, 0x88, 0x3f, 0x9c \
38     }                                                \
39   }
40 
41 /**
42  * Internal interface implemented by script elements
43  */
44 class nsIScriptElement : public nsIScriptLoaderObserver {
45  public:
NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTELEMENT_IID)46   NS_DECLARE_STATIC_IID_ACCESSOR(NS_ISCRIPTELEMENT_IID)
47 
48   explicit nsIScriptElement(mozilla::dom::FromParser aFromParser)
49       : mLineNumber(1),
50         mColumnNumber(1),
51         mAlreadyStarted(false),
52         mMalformed(false),
53         mDoneAddingChildren(aFromParser == mozilla::dom::NOT_FROM_PARSER ||
54                             aFromParser == mozilla::dom::FROM_PARSER_FRAGMENT),
55         mForceAsync(aFromParser == mozilla::dom::NOT_FROM_PARSER ||
56                     aFromParser == mozilla::dom::FROM_PARSER_FRAGMENT),
57         mFrozen(false),
58         mIsModule(false),
59         mDefer(false),
60         mAsync(false),
61         mExternal(false),
62         mParserCreated(aFromParser == mozilla::dom::FROM_PARSER_FRAGMENT
63                            ? mozilla::dom::NOT_FROM_PARSER
64                            : aFromParser),
65         // Fragment parser-created scripts (if executable)
66         // behave like script-created scripts.
67         mCreatorParser(nullptr) {}
68 
69   /**
70    * Content type identifying the scripting language. Can be empty, in
71    * which case javascript will be assumed.
72    * Return false if type attribute is not found.
73    */
74   virtual bool GetScriptType(nsAString& type) = 0;
75 
76   /**
77    * Location of script source text. Can return null, in which case
78    * this is assumed to be an inline script element.
79    */
GetScriptURI()80   nsIURI* GetScriptURI() {
81     MOZ_ASSERT(mFrozen, "Not ready for this call yet!");
82     return mUri;
83   }
84 
GetScriptURITriggeringPrincipal()85   nsIPrincipal* GetScriptURITriggeringPrincipal() {
86     MOZ_ASSERT(mFrozen, "Not ready for this call yet!");
87     return mSrcTriggeringPrincipal;
88   }
89 
90   /**
91    * Script source text for inline script elements.
92    */
93   virtual void GetScriptText(nsAString& text) = 0;
94 
95   virtual void GetScriptCharset(nsAString& charset) = 0;
96 
97   /**
98    * Freezes the return values of the following methods so that subsequent
99    * modifications to the attributes don't change execution behavior:
100    *  - GetScriptIsModule()
101    *  - GetScriptDeferred()
102    *  - GetScriptAsync()
103    *  - GetScriptURI()
104    *  - GetScriptExternal()
105    */
106   virtual void FreezeExecutionAttrs(mozilla::dom::Document*) = 0;
107 
108   /**
109    * Is the script a module script. Currently only supported by HTML scripts.
110    */
GetScriptIsModule()111   bool GetScriptIsModule() {
112     MOZ_ASSERT(mFrozen, "Not ready for this call yet!");
113     return mIsModule;
114   }
115 
116   /**
117    * Is the script deferred. Currently only supported by HTML scripts.
118    */
GetScriptDeferred()119   bool GetScriptDeferred() {
120     MOZ_ASSERT(mFrozen, "Not ready for this call yet!");
121     return mDefer;
122   }
123 
124   /**
125    * Is the script async. Currently only supported by HTML scripts.
126    */
GetScriptAsync()127   bool GetScriptAsync() {
128     MOZ_ASSERT(mFrozen, "Not ready for this call yet!");
129     return mAsync;
130   }
131 
132   /**
133    * Is the script an external script?
134    */
GetScriptExternal()135   bool GetScriptExternal() {
136     MOZ_ASSERT(mFrozen, "Not ready for this call yet!");
137     return mExternal;
138   }
139 
140   /**
141    * Returns how the element was created.
142    */
GetParserCreated()143   mozilla::dom::FromParser GetParserCreated() { return mParserCreated; }
144 
SetScriptLineNumber(uint32_t aLineNumber)145   void SetScriptLineNumber(uint32_t aLineNumber) { mLineNumber = aLineNumber; }
146 
GetScriptLineNumber()147   uint32_t GetScriptLineNumber() { return mLineNumber; }
148 
SetScriptColumnNumber(uint32_t aColumnNumber)149   void SetScriptColumnNumber(uint32_t aColumnNumber) {
150     mColumnNumber = aColumnNumber;
151   }
152 
GetScriptColumnNumber()153   uint32_t GetScriptColumnNumber() { return mColumnNumber; }
154 
SetIsMalformed()155   void SetIsMalformed() { mMalformed = true; }
156 
IsMalformed()157   bool IsMalformed() { return mMalformed; }
158 
PreventExecution()159   void PreventExecution() { mAlreadyStarted = true; }
160 
LoseParserInsertedness()161   void LoseParserInsertedness() {
162     mUri = nullptr;
163     mCreatorParser = nullptr;
164     mParserCreated = mozilla::dom::NOT_FROM_PARSER;
165     mForceAsync = !GetAsyncState();
166 
167     // Reset state set by FreezeExecutionAttrs().
168     mFrozen = false;
169     mIsModule = false;
170     mExternal = false;
171     mAsync = false;
172     mDefer = false;
173   }
174 
175   void SetCreatorParser(nsIParser* aParser);
176 
177   /**
178    * Unblocks the creator parser
179    */
180   void UnblockParser();
181 
182   /**
183    * Attempts to resume parsing asynchronously
184    */
185   void ContinueParserAsync();
186 
187   /**
188    * Informs the creator parser that the evaluation of this script is starting
189    */
190   void BeginEvaluating();
191 
192   /**
193    * Informs the creator parser that the evaluation of this script is ending
194    */
195   void EndEvaluating();
196 
197   /**
198    * Retrieves a pointer to the creator parser if this has one or null if not
199    */
200   already_AddRefed<nsIParser> GetCreatorParser();
201 
202   /**
203    * This method is called when the parser finishes creating the script
204    * element's children, if any are present.
205    *
206    * @return whether the parser will be blocked while this script is being
207    *         loaded
208    */
AttemptToExecute()209   bool AttemptToExecute() {
210     mDoneAddingChildren = true;
211     bool block = MaybeProcessScript();
212     if (!mAlreadyStarted) {
213       // Need to lose parser-insertedness here to allow another script to cause
214       // execution later.
215       LoseParserInsertedness();
216     }
217     return block;
218   }
219 
220   /**
221    * Get the CORS mode of the script element
222    */
GetCORSMode()223   virtual mozilla::CORSMode GetCORSMode() const {
224     /* Default to no CORS */
225     return mozilla::CORS_NONE;
226   }
227 
228   /**
229    * Get referrer policy of the script element
230    */
231   virtual mozilla::dom::ReferrerPolicy GetReferrerPolicy();
232 
233   /**
234    * Fire an error event
235    */
236   virtual nsresult FireErrorEvent() = 0;
237 
238  protected:
239   /**
240    * Processes the script if it's in the document-tree and links to or
241    * contains a script. Once it has been evaluated there is no way to make it
242    * reevaluate the script, you'll have to create a new element. This also means
243    * that when adding a src attribute to an element that already contains an
244    * inline script, the script referenced by the src attribute will not be
245    * loaded.
246    *
247    * In order to be able to use multiple childNodes, or to use the
248    * fallback mechanism of using both inline script and linked script you have
249    * to add all attributes and childNodes before adding the element to the
250    * document-tree.
251    *
252    * @return whether the parser will be blocked while this script is being
253    *         loaded
254    */
255   virtual bool MaybeProcessScript() = 0;
256 
257   /**
258    * Since we've removed the XPCOM interface to HTML elements, we need a way to
259    * retreive async state from script elements without bringing the type in.
260    */
261   virtual bool GetAsyncState() = 0;
262 
263   /**
264    * The start line number of the script.
265    */
266   uint32_t mLineNumber;
267 
268   /**
269    * The start column number of the script.
270    */
271   uint32_t mColumnNumber;
272 
273   /**
274    * The "already started" flag per HTML5.
275    */
276   bool mAlreadyStarted;
277 
278   /**
279    * The script didn't have an end tag.
280    */
281   bool mMalformed;
282 
283   /**
284    * False if parser-inserted but the parser hasn't triggered running yet.
285    */
286   bool mDoneAddingChildren;
287 
288   /**
289    * If true, the .async property returns true instead of reflecting the
290    * content attribute.
291    */
292   bool mForceAsync;
293 
294   /**
295    * Whether src, defer and async are frozen.
296    */
297   bool mFrozen;
298 
299   /**
300    * The effective moduleness.
301    */
302   bool mIsModule;
303 
304   /**
305    * The effective deferredness.
306    */
307   bool mDefer;
308 
309   /**
310    * The effective asyncness.
311    */
312   bool mAsync;
313 
314   /**
315    * The effective externalness. A script can be external with mUri being null
316    * if the src attribute contained an invalid URL string.
317    */
318   bool mExternal;
319 
320   /**
321    * Whether this element was parser-created.
322    */
323   mozilla::dom::FromParser mParserCreated;
324 
325   /**
326    * The effective src (or null if no src).
327    */
328   nsCOMPtr<nsIURI> mUri;
329 
330   /**
331    * The triggering principal for the src URL.
332    */
333   nsCOMPtr<nsIPrincipal> mSrcTriggeringPrincipal;
334 
335   /**
336    * The creator parser of a non-defer, non-async parser-inserted script.
337    */
338   nsWeakPtr mCreatorParser;
339 };
340 
341 NS_DEFINE_STATIC_IID_ACCESSOR(nsIScriptElement, NS_ISCRIPTELEMENT_IID)
342 
343 #endif  // nsIScriptElement_h___
344