Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/dom/ScriptLoadRequest.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_ScriptLoadRequest_h
8
#define mozilla_dom_ScriptLoadRequest_h
9
10
#include "mozilla/CORSMode.h"
11
#include "mozilla/dom/SRIMetadata.h"
12
#include "mozilla/LinkedList.h"
13
#include "mozilla/Maybe.h"
14
#include "mozilla/net/ReferrerPolicy.h"
15
#include "mozilla/Variant.h"
16
#include "mozilla/Vector.h"
17
#include "nsCOMPtr.h"
18
#include "nsCycleCollectionParticipant.h"
19
#include "nsIScriptElement.h"
20
21
class nsICacheInfoChannel;
22
23
namespace mozilla {
24
namespace dom {
25
26
class ModuleLoadRequest;
27
class ScriptLoadRequestList;
28
29
enum class ScriptKind {
30
  eClassic,
31
  eModule
32
};
33
34
/*
35
 * Some options used when fetching script resources. This only loosely
36
 * corresponds to HTML's "script fetch options".
37
 *
38
 * These are common to all modules in a module graph, and hence a single
39
 * instance is shared by all ModuleLoadRequest objects in a graph.
40
 */
41
42
class ScriptFetchOptions
43
{
44
  ~ScriptFetchOptions();
45
46
public:
47
  NS_INLINE_DECL_CYCLE_COLLECTING_NATIVE_REFCOUNTING(ScriptFetchOptions)
48
  NS_DECL_CYCLE_COLLECTION_NATIVE_CLASS(ScriptFetchOptions)
49
50
  ScriptFetchOptions(mozilla::CORSMode aCORSMode,
51
                     mozilla::net::ReferrerPolicy aReferrerPolicy,
52
                     nsIScriptElement* aElement,
53
                     nsIPrincipal* aTriggeringPrincipal);
54
55
  const mozilla::CORSMode mCORSMode;
56
  const mozilla::net::ReferrerPolicy mReferrerPolicy;
57
  nsCOMPtr<nsIScriptElement> mElement;
58
  nsCOMPtr<nsIPrincipal> mTriggeringPrincipal;
59
};
60
61
/*
62
 * A class that handles loading and evaluation of <script> elements.
63
 */
64
65
class ScriptLoadRequest : public nsISupports,
66
                          private mozilla::LinkedListElement<ScriptLoadRequest>
67
{
68
  typedef LinkedListElement<ScriptLoadRequest> super;
69
70
  // Allow LinkedListElement<ScriptLoadRequest> to cast us to itself as needed.
71
  friend class mozilla::LinkedListElement<ScriptLoadRequest>;
72
  friend class ScriptLoadRequestList;
73
74
protected:
75
  virtual ~ScriptLoadRequest();
76
77
public:
78
  ScriptLoadRequest(ScriptKind aKind,
79
                    nsIURI* aURI,
80
                    ScriptFetchOptions* aFetchOptions,
81
                    const SRIMetadata &aIntegrity,
82
                    nsIURI* aReferrer);
83
84
  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
85
  NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(ScriptLoadRequest)
86
87
  bool IsModuleRequest() const
88
0
  {
89
0
    return mKind == ScriptKind::eModule;
90
0
  }
91
92
  ModuleLoadRequest* AsModuleRequest();
93
94
  void FireScriptAvailable(nsresult aResult)
95
0
  {
96
0
    bool isInlineClassicScript = mIsInline && !IsModuleRequest();
97
0
    Element()->ScriptAvailable(aResult, Element(), isInlineClassicScript, mURI,
98
0
                              mLineNo);
99
0
  }
100
  void FireScriptEvaluated(nsresult aResult)
101
0
  {
102
0
    Element()->ScriptEvaluated(aResult, Element(), mIsInline);
103
0
  }
104
105
  bool IsPreload()
106
0
  {
107
0
    return Element() == nullptr;
108
0
  }
109
110
  virtual void Cancel();
111
112
  bool IsCanceled() const
113
0
  {
114
0
    return mIsCanceled;
115
0
  }
116
117
  virtual void SetReady();
118
119
  JS::OffThreadToken** OffThreadTokenPtr()
120
0
  {
121
0
    return mOffThreadToken ?  &mOffThreadToken : nullptr;
122
0
  }
123
124
  bool IsTracking() const
125
0
  {
126
0
    return mIsTracking;
127
0
  }
128
  void SetIsTracking()
129
0
  {
130
0
    MOZ_ASSERT(!mIsTracking);
131
0
    mIsTracking = true;
132
0
  }
133
134
  enum class Progress : uint8_t {
135
    eLoading,        // Request either source or bytecode
136
    eLoading_Source, // Explicitly Request source stream
137
    eCompiling,
138
    eFetchingImports,
139
    eReady
140
  };
141
142
  bool IsReadyToRun() const
143
0
  {
144
0
    return mProgress == Progress::eReady;
145
0
  }
146
  bool IsLoading() const
147
0
  {
148
0
    return mProgress == Progress::eLoading ||
149
0
           mProgress == Progress::eLoading_Source;
150
0
  }
151
  bool IsLoadingSource() const
152
0
  {
153
0
    return mProgress == Progress::eLoading_Source;
154
0
  }
155
  bool InCompilingStage() const
156
0
  {
157
0
    return mProgress == Progress::eCompiling ||
158
0
           (IsReadyToRun() && mWasCompiledOMT);
159
0
  }
160
161
  // Type of data provided by the nsChannel.
162
  enum class DataType : uint8_t {
163
    eUnknown,
164
    eTextSource,
165
    eBinASTSource,
166
    eBytecode
167
  };
168
169
  bool IsUnknownDataType() const
170
0
  {
171
0
    return mDataType == DataType::eUnknown;
172
0
  }
173
  bool IsTextSource() const
174
0
  {
175
0
    return mDataType == DataType::eTextSource;
176
0
  }
177
  bool IsBinASTSource() const
178
0
  {
179
0
#ifdef JS_BUILD_BINAST
180
0
    return mDataType == DataType::eBinASTSource;
181
#else
182
    return false;
183
#endif
184
  }
185
  bool IsSource() const
186
0
  {
187
0
    return IsTextSource() || IsBinASTSource();
188
0
  }
189
  bool IsBytecode() const
190
0
  {
191
0
    return mDataType == DataType::eBytecode;
192
0
  }
193
194
  void SetUnknownDataType();
195
  void SetTextSource();
196
  void SetBinASTSource();
197
  void SetBytecode();
198
199
  using ScriptTextBuffer = Vector<char16_t, 0, JSMallocAllocPolicy>;
200
  using BinASTSourceBuffer = Vector<uint8_t>;
201
202
  const ScriptTextBuffer& ScriptText() const
203
0
  {
204
0
    MOZ_ASSERT(IsTextSource());
205
0
    return mScriptData->as<ScriptTextBuffer>();
206
0
  }
207
  ScriptTextBuffer& ScriptText()
208
0
  {
209
0
    MOZ_ASSERT(IsTextSource());
210
0
    return mScriptData->as<ScriptTextBuffer>();
211
0
  }
212
  const BinASTSourceBuffer& ScriptBinASTData() const
213
0
  {
214
0
    MOZ_ASSERT(IsBinASTSource());
215
0
    return mScriptData->as<BinASTSourceBuffer>();
216
0
  }
217
  BinASTSourceBuffer& ScriptBinASTData()
218
0
  {
219
0
    MOZ_ASSERT(IsBinASTSource());
220
0
    return mScriptData->as<BinASTSourceBuffer>();
221
0
  }
222
223
  enum class ScriptMode : uint8_t {
224
    eBlocking,
225
    eDeferred,
226
    eAsync
227
  };
228
229
  void SetScriptMode(bool aDeferAttr, bool aAsyncAttr);
230
231
  bool IsBlockingScript() const
232
0
  {
233
0
    return mScriptMode == ScriptMode::eBlocking;
234
0
  }
235
236
  bool IsDeferredScript() const
237
0
  {
238
0
    return mScriptMode == ScriptMode::eDeferred;
239
0
  }
240
241
  bool IsAsyncScript() const
242
0
  {
243
0
    return mScriptMode == ScriptMode::eAsync;
244
0
  }
245
246
  virtual bool IsTopLevel() const
247
0
  {
248
0
    // Classic scripts are always top level.
249
0
    return true;
250
0
  }
251
252
  mozilla::CORSMode CORSMode() const
253
0
  {
254
0
    return mFetchOptions->mCORSMode;
255
0
  }
256
  mozilla::net::ReferrerPolicy ReferrerPolicy() const
257
0
  {
258
0
    return mFetchOptions->mReferrerPolicy;
259
0
  }
260
  nsIScriptElement* Element() const
261
0
  {
262
0
    return mFetchOptions->mElement;
263
0
  }
264
  nsIPrincipal* TriggeringPrincipal() const
265
0
  {
266
0
    return mFetchOptions->mTriggeringPrincipal;
267
0
  }
268
269
  void SetElement(nsIScriptElement* aElement)
270
0
  {
271
0
    // Called when a preload request is later used for an actual request.
272
0
    MOZ_ASSERT(aElement);
273
0
    MOZ_ASSERT(!Element());
274
0
    mFetchOptions->mElement = aElement;
275
0
  }
276
277
  bool ShouldAcceptBinASTEncoding() const;
278
279
  void ClearScriptSource();
280
281
  void MaybeCancelOffThreadScript();
282
  void DropBytecodeCacheReferences();
283
284
  using super::getNext;
285
  using super::isInList;
286
287
  const ScriptKind mKind; // Whether this is a classic script or a module script.
288
  ScriptMode mScriptMode; // Whether this is a blocking, defer or async script.
289
  Progress mProgress;     // Are we still waiting for a load to complete?
290
  DataType mDataType;     // Does this contain Source or Bytecode?
291
  bool mScriptFromHead;   // Synchronous head script block loading of other non js/css content.
292
  bool mIsInline;         // Is the script inline or loaded?
293
  bool mHasSourceMapURL;  // Does the HTTP header have a source map url?
294
  bool mInDeferList;      // True if we live in mDeferRequests.
295
  bool mInAsyncList;      // True if we live in mLoadingAsyncRequests or mLoadedAsyncRequests.
296
  bool mIsNonAsyncScriptInserted; // True if we live in mNonAsyncExternalScriptInsertedRequests
297
  bool mIsXSLT;           // True if we live in mXSLTRequests.
298
  bool mIsCanceled;       // True if we have been explicitly canceled.
299
  bool mWasCompiledOMT;   // True if the script has been compiled off main thread.
300
  bool mIsTracking;       // True if the script comes from a source on our tracking protection list.
301
302
  RefPtr<ScriptFetchOptions> mFetchOptions;
303
304
  JS::OffThreadToken* mOffThreadToken; // Off-thread parsing token.
305
  nsString mSourceMapURL; // Holds source map url for loaded scripts
306
307
  // Holds the top-level JSScript that corresponds to the current source, once
308
  // it is parsed, and planned to be saved in the bytecode cache.
309
  JS::Heap<JSScript*> mScript;
310
311
  // Holds script source data for non-inline scripts. Don't use nsString so we
312
  // can give ownership to jsapi. Holds either char16_t source text characters
313
  // or BinAST encoded bytes depending on mSourceEncoding.
314
  Maybe<Variant<ScriptTextBuffer, BinASTSourceBuffer>> mScriptData;
315
316
  // The length of script source text, set when reading completes. This is used
317
  // since mScriptData is cleared when the source is passed to the JS engine.
318
  size_t mScriptTextLength;
319
320
  // Holds the SRI serialized hash and the script bytecode for non-inline
321
  // scripts.
322
  mozilla::Vector<uint8_t> mScriptBytecode;
323
  uint32_t mBytecodeOffset; // Offset of the bytecode in mScriptBytecode
324
325
  const nsCOMPtr<nsIURI> mURI;
326
  nsCOMPtr<nsIPrincipal> mOriginPrincipal;
327
  nsAutoCString mURL;     // Keep the URI's filename alive during off thread parsing.
328
  int32_t mLineNo;
329
  const SRIMetadata mIntegrity;
330
  const nsCOMPtr<nsIURI> mReferrer;
331
332
  // Holds the Cache information, which is used to register the bytecode
333
  // on the cache entry, such that we can load it the next time.
334
  nsCOMPtr<nsICacheInfoChannel> mCacheInfo;
335
};
336
337
class ScriptLoadRequestList : private mozilla::LinkedList<ScriptLoadRequest>
338
{
339
  typedef mozilla::LinkedList<ScriptLoadRequest> super;
340
341
public:
342
  ~ScriptLoadRequestList();
343
344
  void Clear();
345
346
#ifdef DEBUG
347
  bool Contains(ScriptLoadRequest* aElem) const;
348
#endif // DEBUG
349
350
  using super::getFirst;
351
  using super::isEmpty;
352
353
  void AppendElement(ScriptLoadRequest* aElem)
354
0
  {
355
0
    MOZ_ASSERT(!aElem->isInList());
356
0
    NS_ADDREF(aElem);
357
0
    insertBack(aElem);
358
0
  }
359
360
  MOZ_MUST_USE
361
  already_AddRefed<ScriptLoadRequest> Steal(ScriptLoadRequest* aElem)
362
0
  {
363
0
    aElem->removeFrom(*this);
364
0
    return dont_AddRef(aElem);
365
0
  }
366
367
  MOZ_MUST_USE
368
  already_AddRefed<ScriptLoadRequest> StealFirst()
369
0
  {
370
0
    MOZ_ASSERT(!isEmpty());
371
0
    return Steal(getFirst());
372
0
  }
373
374
  void Remove(ScriptLoadRequest* aElem)
375
0
  {
376
0
    aElem->removeFrom(*this);
377
0
    NS_RELEASE(aElem);
378
0
  }
379
};
380
381
void
382
ImplCycleCollectionUnlink(ScriptLoadRequestList& aField);
383
384
void
385
ImplCycleCollectionTraverse(nsCycleCollectionTraversalCallback& aCallback,
386
                            ScriptLoadRequestList& aField,
387
                            const char* aName,
388
                            uint32_t aFlags);
389
390
} // namespace dom
391
} // namespace mozilla
392
393
#endif // mozilla_dom_ScriptLoadRequest_h