Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/dom/ScriptLoader.h
Line
Count
Source (jump to first uncovered line)
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 mozilla_dom_ScriptLoader_h
8
#define mozilla_dom_ScriptLoader_h
9
10
#include "nsCOMPtr.h"
11
#include "nsRefPtrHashtable.h"
12
#include "mozilla/Encoding.h"
13
#include "nsIScriptElement.h"
14
#include "nsCOMArray.h"
15
#include "nsCycleCollectionParticipant.h"
16
#include "nsTArray.h"
17
#include "nsAutoPtr.h"
18
#include "nsICacheInfoChannel.h"
19
#include "nsIDocument.h"
20
#include "nsIIncrementalStreamLoader.h"
21
#include "nsURIHashKey.h"
22
#include "mozilla/CORSMode.h"
23
#include "mozilla/dom/ScriptLoadRequest.h"
24
#include "mozilla/dom/SRIMetadata.h"
25
#include "mozilla/dom/SRICheck.h"
26
#include "mozilla/Maybe.h"
27
#include "mozilla/MozPromise.h"
28
#include "mozilla/net/ReferrerPolicy.h"
29
#include "mozilla/StaticPrefs.h"
30
#include "mozilla/Vector.h"
31
32
class nsIURI;
33
34
namespace JS {
35
  class SourceBufferHolder;
36
} // namespace JS
37
38
namespace mozilla {
39
namespace dom {
40
41
class AutoJSAPI;
42
class ModuleLoadRequest;
43
class ModuleScript;
44
class ScriptLoadHandler;
45
class ScriptRequestProcessor;
46
47
//////////////////////////////////////////////////////////////
48
// Script loader implementation
49
//////////////////////////////////////////////////////////////
50
51
class ScriptLoader final : public nsISupports
52
{
53
  class MOZ_STACK_CLASS AutoCurrentScriptUpdater
54
  {
55
  public:
56
    AutoCurrentScriptUpdater(ScriptLoader* aScriptLoader,
57
                             nsIScriptElement* aCurrentScript)
58
      : mOldScript(aScriptLoader->mCurrentScript)
59
      , mScriptLoader(aScriptLoader)
60
    {
61
      nsCOMPtr<nsINode> node = do_QueryInterface(aCurrentScript);
62
      mScriptLoader->mCurrentScript =
63
        node && !node->IsInShadowTree() ? aCurrentScript : nullptr;
64
    }
65
66
    ~AutoCurrentScriptUpdater()
67
    {
68
      mScriptLoader->mCurrentScript.swap(mOldScript);
69
    }
70
71
  private:
72
    nsCOMPtr<nsIScriptElement> mOldScript;
73
    ScriptLoader* mScriptLoader;
74
  };
75
76
  friend class ModuleLoadRequest;
77
  friend class ScriptRequestProcessor;
78
  friend class ScriptLoadHandler;
79
  friend class AutoCurrentScriptUpdater;
80
81
public:
82
  explicit ScriptLoader(nsIDocument* aDocument);
83
84
  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
85
  NS_DECL_CYCLE_COLLECTION_CLASS(ScriptLoader)
86
87
  /**
88
   * The loader maintains a weak reference to the document with
89
   * which it is initialized. This call forces the reference to
90
   * be dropped.
91
   */
92
  void DropDocumentReference()
93
0
  {
94
0
    mDocument = nullptr;
95
0
  }
96
97
  /**
98
   * Add an observer for all scripts loaded through this loader.
99
   *
100
   * @param aObserver observer for all script processing.
101
   */
102
  nsresult AddObserver(nsIScriptLoaderObserver* aObserver)
103
0
  {
104
0
    return mObservers.AppendObject(aObserver) ? NS_OK :
105
0
      NS_ERROR_OUT_OF_MEMORY;
106
0
  }
107
108
  /**
109
   * Remove an observer.
110
   *
111
   * @param aObserver observer to be removed
112
   */
113
  void RemoveObserver(nsIScriptLoaderObserver* aObserver)
114
0
  {
115
0
    mObservers.RemoveObject(aObserver);
116
0
  }
117
118
  /**
119
   * Process a script element. This will include both loading the
120
   * source of the element if it is not inline and evaluating
121
   * the script itself.
122
   *
123
   * If the script is an inline script that can be executed immediately
124
   * (i.e. there are no other scripts pending) then ScriptAvailable
125
   * and ScriptEvaluated will be called before the function returns.
126
   *
127
   * If true is returned the script could not be executed immediately.
128
   * In this case ScriptAvailable is guaranteed to be called at a later
129
   * point (as well as possibly ScriptEvaluated).
130
   *
131
   * @param aElement The element representing the script to be loaded and
132
   *        evaluated.
133
   */
134
  bool ProcessScriptElement(nsIScriptElement* aElement);
135
136
  /**
137
   * Gets the currently executing script. This is useful if you want to
138
   * generate a unique key based on the currently executing script.
139
   */
140
  nsIScriptElement* GetCurrentScript()
141
0
  {
142
0
    return mCurrentScript;
143
0
  }
144
145
  nsIScriptElement* GetCurrentParserInsertedScript()
146
0
  {
147
0
    return mCurrentParserInsertedScript;
148
0
  }
149
150
  /**
151
   * Whether the loader is enabled or not.
152
   * When disabled, processing of new script elements is disabled.
153
   * Any call to ProcessScriptElement() will return false. Note that
154
   * this DOES NOT disable currently loading or executing scripts.
155
   */
156
  bool GetEnabled()
157
0
  {
158
0
    return mEnabled;
159
0
  }
160
161
  void SetEnabled(bool aEnabled)
162
0
  {
163
0
    if (!mEnabled && aEnabled) {
164
0
      ProcessPendingRequestsAsync();
165
0
    }
166
0
    mEnabled = aEnabled;
167
0
  }
168
169
  /**
170
   * Add/remove a blocker for parser-blocking scripts (and XSLT
171
   * scripts). Blockers will stop such scripts from executing, but not from
172
   * loading.
173
   */
174
  void AddParserBlockingScriptExecutionBlocker()
175
0
  {
176
0
    ++mParserBlockingBlockerCount;
177
0
  }
178
179
  void RemoveParserBlockingScriptExecutionBlocker()
180
0
  {
181
0
    if (!--mParserBlockingBlockerCount && ReadyToExecuteScripts()) {
182
0
      ProcessPendingRequestsAsync();
183
0
    }
184
0
  }
185
186
  /**
187
   * Add/remove a blocker for execution of all scripts.  Blockers will stop
188
   * scripts from executing, but not from loading.
189
   */
190
  void AddExecuteBlocker()
191
0
  {
192
0
    ++mBlockerCount;
193
0
  }
194
195
  void RemoveExecuteBlocker()
196
0
  {
197
0
    MOZ_ASSERT(mBlockerCount);
198
0
    if (!--mBlockerCount) {
199
0
      ProcessPendingRequestsAsync();
200
0
    }
201
0
  }
202
203
  /**
204
   * Convert the given buffer to a UTF-16 string.
205
   * @param aChannel     Channel corresponding to the data. May be null.
206
   * @param aData        The data to convert
207
   * @param aLength      Length of the data
208
   * @param aHintCharset Hint for the character set (e.g., from a charset
209
   *                     attribute). May be the empty string.
210
   * @param aDocument    Document which the data is loaded for. Must not be
211
   *                     null.
212
   * @param aBufOut      [out] char16_t array allocated by ConvertToUTF16 and
213
   *                     containing data converted to unicode.  Caller must
214
   *                     js_free() this data when no longer needed.
215
   * @param aLengthOut   [out] Length of array returned in aBufOut in number
216
   *                     of char16_t code units.
217
   */
218
  static nsresult ConvertToUTF16(nsIChannel* aChannel, const uint8_t* aData,
219
                                 uint32_t aLength,
220
                                 const nsAString& aHintCharset,
221
                                 nsIDocument* aDocument,
222
                                 char16_t*& aBufOut, size_t& aLengthOut);
223
224
  static inline nsresult
225
  ConvertToUTF16(nsIChannel* aChannel, const uint8_t* aData,
226
                 uint32_t aLength, const nsAString& aHintCharset,
227
                 nsIDocument* aDocument,
228
                 JS::UniqueTwoByteChars& aBufOut, size_t& aLengthOut)
229
0
  {
230
0
    char16_t* bufOut;
231
0
    nsresult rv = ConvertToUTF16(aChannel, aData, aLength, aHintCharset,
232
0
                                 aDocument, bufOut, aLengthOut);
233
0
    if (NS_SUCCEEDED(rv)) {
234
0
      aBufOut.reset(bufOut);
235
0
    }
236
0
    return rv;
237
0
  };
238
239
  /**
240
   * Handle the completion of a stream.  This is called by the
241
   * ScriptLoadHandler object which observes the IncrementalStreamLoader
242
   * loading the script. The streamed content is expected to be stored on the
243
   * aRequest argument.
244
   */
245
  nsresult OnStreamComplete(nsIIncrementalStreamLoader* aLoader,
246
                            ScriptLoadRequest* aRequest,
247
                            nsresult aChannelStatus,
248
                            nsresult aSRIStatus,
249
                            SRICheckDataVerifier* aSRIDataVerifier);
250
251
  /**
252
   * Returns wether any request is queued, and not executed yet.
253
   */
254
  bool HasPendingRequests();
255
256
  /**
257
   * Processes any pending requests that are ready for processing.
258
   */
259
  void ProcessPendingRequests();
260
261
  /**
262
   * Starts deferring deferred scripts and puts them in the mDeferredRequests
263
   * queue instead.
264
   */
265
  void BeginDeferringScripts()
266
0
  {
267
0
    mDeferEnabled = true;
268
0
    if (mDocument) {
269
0
      mDocument->BlockOnload();
270
0
    }
271
0
  }
272
273
  /**
274
   * Notifies the script loader that parsing is done.  If aTerminated is true,
275
   * this will drop any pending scripts that haven't run yet.  Otherwise, it
276
   * will stops deferring scripts and immediately processes the
277
   * mDeferredRequests queue.
278
   *
279
   * WARNING: This function will synchronously execute content scripts, so be
280
   * prepared that the world might change around you.
281
   */
282
  void ParsingComplete(bool aTerminated);
283
284
  /**
285
   * Returns the number of pending scripts, deferred or not.
286
   */
287
  uint32_t HasPendingOrCurrentScripts()
288
0
  {
289
0
    return mCurrentScript || mParserBlockingRequest;
290
0
  }
291
292
  /**
293
   * Adds aURI to the preload list and starts loading it.
294
   *
295
   * @param aURI The URI of the external script.
296
   * @param aCharset The charset parameter for the script.
297
   * @param aType The type parameter for the script.
298
   * @param aCrossOrigin The crossorigin attribute for the script.
299
   *                     Void if not present.
300
   * @param aIntegrity The expect hash url, if avail, of the request
301
   * @param aScriptFromHead Whether or not the script was a child of head
302
   */
303
  virtual void PreloadURI(nsIURI* aURI,
304
                          const nsAString& aCharset,
305
                          const nsAString& aType,
306
                          const nsAString& aCrossOrigin,
307
                          const nsAString& aIntegrity,
308
                          bool aScriptFromHead,
309
                          bool aAsync,
310
                          bool aDefer,
311
                          bool aNoModule,
312
                          const mozilla::net::ReferrerPolicy aReferrerPolicy);
313
314
  /**
315
   * Process a request that was deferred so that the script could be compiled
316
   * off thread.
317
   */
318
  nsresult ProcessOffThreadRequest(ScriptLoadRequest* aRequest);
319
320
  bool AddPendingChildLoader(ScriptLoader* aChild)
321
  {
322
    return mPendingChildLoaders.AppendElement(aChild) != nullptr;
323
  }
324
325
  mozilla::dom::DocGroup* GetDocGroup() const
326
  {
327
    return mDocument->GetDocGroup();
328
  }
329
330
  /**
331
   * Register the fact that we saw the load event, and that we need to save the
332
   * bytecode at the next loop cycle unless new scripts are waiting in the
333
   * pipeline.
334
   */
335
  void LoadEventFired();
336
337
  /**
338
   * Destroy and prevent the ScriptLoader or the ScriptLoadRequests from owning
339
   * any references to the JSScript or to the Request which might be used for
340
   * caching the encoded bytecode.
341
   */
342
  void Destroy()
343
0
  {
344
0
    GiveUpBytecodeEncoding();
345
0
  }
346
347
private:
348
  virtual ~ScriptLoader();
349
350
  ScriptLoadRequest* CreateLoadRequest(ScriptKind aKind,
351
                                       nsIURI* aURI,
352
                                       nsIScriptElement* aElement,
353
                                       nsIPrincipal* aTriggeringPrincipal,
354
                                       mozilla::CORSMode aCORSMode,
355
                                       const SRIMetadata& aIntegrity,
356
                                       mozilla::net::ReferrerPolicy aReferrerPolicy);
357
358
  /**
359
   * Unblocks the creator parser of the parser-blocking scripts.
360
   */
361
  void UnblockParser(ScriptLoadRequest* aParserBlockingRequest);
362
363
  /**
364
   * Asynchronously resumes the creator parser of the parser-blocking scripts.
365
   */
366
  void ContinueParserAsync(ScriptLoadRequest* aParserBlockingRequest);
367
368
369
  bool ProcessExternalScript(nsIScriptElement* aElement,
370
                             ScriptKind aScriptKind,
371
                             nsAutoString aTypeAttr,
372
                             nsIContent* aScriptContent);
373
374
  bool ProcessInlineScript(nsIScriptElement* aElement,
375
                           ScriptKind aScriptKind);
376
377
  ScriptLoadRequest* LookupPreloadRequest(nsIScriptElement* aElement,
378
                                          ScriptKind aScriptKind);
379
380
  void GetSRIMetadata(const nsAString& aIntegrityAttr,
381
                      SRIMetadata *aMetadataOut);
382
383
  /**
384
   * Helper function to check the content policy for a given request.
385
   */
386
  static nsresult CheckContentPolicy(nsIDocument* aDocument,
387
                                     nsISupports* aContext,
388
                                     nsIURI* aURI,
389
                                     const nsAString& aType,
390
                                     bool aIsPreLoad);
391
392
  /**
393
   * Start a load for aRequest's URI.
394
   */
395
  nsresult StartLoad(ScriptLoadRequest* aRequest);
396
397
  /**
398
   * Abort the current stream, and re-start with a new load request from scratch
399
   * without requesting any alternate data. Returns NS_BINDING_RETARGETED on
400
   * success, as this error code is used to abort the input stream.
401
   */
402
  nsresult RestartLoad(ScriptLoadRequest* aRequest);
403
404
  void HandleLoadError(ScriptLoadRequest *aRequest, nsresult aResult);
405
406
  static bool BinASTEncodingEnabled()
407
  {
408
#ifdef JS_BUILD_BINAST
409
    return StaticPrefs::dom_script_loader_binast_encoding_enabled();
410
#else
411
    return false;
412
#endif
413
  }
414
415
  /**
416
   * Process any pending requests asynchronously (i.e. off an event) if there
417
   * are any. Note that this is a no-op if there aren't any currently pending
418
   * requests.
419
   *
420
   * This function is virtual to allow cross-library calls to SetEnabled()
421
   */
422
  virtual void ProcessPendingRequestsAsync();
423
424
  /**
425
   * If true, the loader is ready to execute parser-blocking scripts, and so are
426
   * all its ancestors.  If the loader itself is ready but some ancestor is not,
427
   * this function will add an execute blocker and ask the ancestor to remove it
428
   * once it becomes ready.
429
   */
430
  bool ReadyToExecuteParserBlockingScripts();
431
432
  /**
433
   * Return whether just this loader is ready to execute parser-blocking
434
   * scripts.
435
   */
436
  bool SelfReadyToExecuteParserBlockingScripts()
437
  {
438
    return ReadyToExecuteScripts() && !mParserBlockingBlockerCount;
439
  }
440
441
  /**
442
   * Return whether this loader is ready to execute scripts in general.
443
   */
444
  bool ReadyToExecuteScripts()
445
0
  {
446
0
    return mEnabled && !mBlockerCount;
447
0
  }
448
449
  nsresult VerifySRI(ScriptLoadRequest *aRequest,
450
                     nsIIncrementalStreamLoader* aLoader,
451
                     nsresult aSRIStatus,
452
                     SRICheckDataVerifier* aSRIDataVerifier) const;
453
454
  nsresult SaveSRIHash(ScriptLoadRequest *aRequest,
455
                       SRICheckDataVerifier* aSRIDataVerifier) const;
456
457
  void ReportErrorToConsole(ScriptLoadRequest *aRequest, nsresult aResult) const;
458
459
  nsresult AttemptAsyncScriptCompile(ScriptLoadRequest* aRequest,
460
                                     bool* aCouldCompileOut);
461
  nsresult ProcessRequest(ScriptLoadRequest* aRequest);
462
  nsresult CompileOffThreadOrProcessRequest(ScriptLoadRequest* aRequest);
463
  void FireScriptAvailable(nsresult aResult,
464
                           ScriptLoadRequest* aRequest);
465
  void FireScriptEvaluated(nsresult aResult,
466
                           ScriptLoadRequest* aRequest);
467
  nsresult EvaluateScript(ScriptLoadRequest* aRequest);
468
469
  /**
470
   * Queue the current script load request to be saved, when the page
471
   * initialization ends. The page initialization end is defined as being the
472
   * time when the load event got received, and when no more scripts are waiting
473
   * to be executed.
474
   */
475
  void RegisterForBytecodeEncoding(ScriptLoadRequest* aRequest);
476
477
  /**
478
   * Check if all conditions are met, i-e that the onLoad event fired and that
479
   * no more script have to be processed.  If all conditions are met, queue an
480
   * event to encode all the bytecode and save them on the cache.
481
   */
482
  void MaybeTriggerBytecodeEncoding();
483
484
  /**
485
   * Iterate over all script load request and save the bytecode of executed
486
   * functions on the cache provided by the channel.
487
   */
488
  void EncodeBytecode();
489
  void EncodeRequestBytecode(JSContext* aCx, ScriptLoadRequest* aRequest);
490
491
  void GiveUpBytecodeEncoding();
492
493
  already_AddRefed<nsIScriptGlobalObject> GetScriptGlobalObject();
494
  nsresult FillCompileOptionsForRequest(const mozilla::dom::AutoJSAPI& jsapi,
495
                                        ScriptLoadRequest* aRequest,
496
                                        JS::Handle<JSObject*> aScopeChain,
497
                                        JS::CompileOptions* aOptions);
498
499
  uint32_t NumberOfProcessors();
500
  nsresult PrepareLoadedRequest(ScriptLoadRequest* aRequest,
501
                                nsIIncrementalStreamLoader* aLoader,
502
                                nsresult aStatus);
503
504
  void AddDeferRequest(ScriptLoadRequest* aRequest);
505
  void AddAsyncRequest(ScriptLoadRequest* aRequest);
506
  bool MaybeRemovedDeferRequests();
507
508
  void MaybeMoveToLoadedList(ScriptLoadRequest* aRequest);
509
510
  mozilla::Maybe<JS::SourceBufferHolder> GetScriptSource(JSContext* aCx,
511
                                                         ScriptLoadRequest* aRequest);
512
513
  void SetModuleFetchStarted(ModuleLoadRequest *aRequest);
514
  void SetModuleFetchFinishedAndResumeWaitingRequests(ModuleLoadRequest* aRequest,
515
                                                      nsresult aResult);
516
517
  bool IsFetchingModule(ModuleLoadRequest* aRequest) const;
518
519
  bool ModuleMapContainsURL(nsIURI* aURL) const;
520
  RefPtr<mozilla::GenericPromise> WaitForModuleFetch(nsIURI* aURL);
521
  ModuleScript* GetFetchedModule(nsIURI* aURL) const;
522
523
  friend JSScript*
524
  HostResolveImportedModule(JSContext* aCx, JS::Handle<JSScript*> aScript,
525
                          JS::Handle<JSString*> aSpecifier);
526
527
  // Returns wether we should save the bytecode of this script after the
528
  // execution of the script.
529
  static bool
530
  ShouldCacheBytecode(ScriptLoadRequest* aRequest);
531
532
  nsresult CreateModuleScript(ModuleLoadRequest* aRequest);
533
  nsresult ProcessFetchedModuleSource(ModuleLoadRequest* aRequest);
534
  void CheckModuleDependenciesLoaded(ModuleLoadRequest* aRequest);
535
  void ProcessLoadedModuleTree(ModuleLoadRequest* aRequest);
536
  bool InstantiateModuleTree(ModuleLoadRequest* aRequest);
537
  JS::Value FindFirstParseError(ModuleLoadRequest* aRequest);
538
  void StartFetchingModuleDependencies(ModuleLoadRequest* aRequest);
539
540
  RefPtr<mozilla::GenericPromise>
541
  StartFetchingModuleAndDependencies(ModuleLoadRequest* aParent, nsIURI* aURI);
542
543
  nsresult AssociateSourceElementsForModuleTree(JSContext* aCx,
544
                                                ModuleLoadRequest* aRequest);
545
546
  nsIDocument* mDocument;                   // [WEAK]
547
  nsCOMArray<nsIScriptLoaderObserver> mObservers;
548
  ScriptLoadRequestList mNonAsyncExternalScriptInsertedRequests;
549
  // mLoadingAsyncRequests holds async requests while they're loading; when they
550
  // have been loaded they are moved to mLoadedAsyncRequests.
551
  ScriptLoadRequestList mLoadingAsyncRequests;
552
  ScriptLoadRequestList mLoadedAsyncRequests;
553
  ScriptLoadRequestList mDeferRequests;
554
  ScriptLoadRequestList mXSLTRequests;
555
  RefPtr<ScriptLoadRequest> mParserBlockingRequest;
556
557
  // List of script load request that are holding a buffer which has to be saved
558
  // on the cache.
559
  ScriptLoadRequestList mBytecodeEncodingQueue;
560
561
  // In mRequests, the additional information here is stored by the element.
562
  struct PreloadInfo
563
  {
564
    RefPtr<ScriptLoadRequest> mRequest;
565
    nsString mCharset;
566
  };
567
568
  friend void ImplCycleCollectionUnlink(ScriptLoader::PreloadInfo& aField);
569
  friend void ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
570
                                          ScriptLoader::PreloadInfo& aField,
571
                                          const char* aName, uint32_t aFlags);
572
573
  struct PreloadRequestComparator
574
  {
575
    bool Equals(const PreloadInfo& aPi, ScriptLoadRequest* const& aRequest) const
576
    {
577
      return aRequest == aPi.mRequest;
578
    }
579
  };
580
581
  struct PreloadURIComparator
582
  {
583
    bool Equals(const PreloadInfo& aPi, nsIURI* const &aURI) const;
584
  };
585
586
  nsTArray<PreloadInfo> mPreloads;
587
588
  nsCOMPtr<nsIScriptElement> mCurrentScript;
589
  nsCOMPtr<nsIScriptElement> mCurrentParserInsertedScript;
590
  nsTArray< RefPtr<ScriptLoader> > mPendingChildLoaders;
591
  uint32_t mParserBlockingBlockerCount;
592
  uint32_t mBlockerCount;
593
  uint32_t mNumberOfProcessors;
594
  bool mEnabled;
595
  bool mDeferEnabled;
596
  bool mDocumentParsingDone;
597
  bool mBlockingDOMContentLoaded;
598
  bool mLoadEventFired;
599
  bool mGiveUpEncoding;
600
601
  // Module map
602
  nsRefPtrHashtable<nsURIHashKey, mozilla::GenericPromise::Private> mFetchingModules;
603
  nsRefPtrHashtable<nsURIHashKey, ModuleScript> mFetchedModules;
604
605
  nsCOMPtr<nsIConsoleReportCollector> mReporter;
606
607
  // Logging
608
  static LazyLogModule gCspPRLog;
609
  static LazyLogModule gScriptLoaderLog;
610
};
611
612
class nsAutoScriptLoaderDisabler
613
{
614
public:
615
  explicit nsAutoScriptLoaderDisabler(nsIDocument* aDoc)
616
0
  {
617
0
    mLoader = aDoc->ScriptLoader();
618
0
    mWasEnabled = mLoader->GetEnabled();
619
0
    if (mWasEnabled) {
620
0
      mLoader->SetEnabled(false);
621
0
    }
622
0
  }
623
624
  ~nsAutoScriptLoaderDisabler()
625
0
  {
626
0
    if (mWasEnabled) {
627
0
      mLoader->SetEnabled(true);
628
0
    }
629
0
  }
630
631
  bool mWasEnabled;
632
  RefPtr<ScriptLoader> mLoader;
633
};
634
635
} // namespace dom
636
} // namespace mozilla
637
638
#endif // mozilla_dom_ScriptLoader_h