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