Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/mozilla/dom/Fetch.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_Fetch_h
8
#define mozilla_dom_Fetch_h
9
10
#include "nsAutoPtr.h"
11
#include "nsIStreamLoader.h"
12
13
#include "nsCOMPtr.h"
14
#include "nsError.h"
15
#include "nsProxyRelease.h"
16
#include "nsString.h"
17
18
#include "mozilla/DebugOnly.h"
19
#include "mozilla/ErrorResult.h"
20
#include "mozilla/dom/AbortSignal.h"
21
#include "mozilla/dom/Promise.h"
22
#include "mozilla/dom/FetchStreamReader.h"
23
#include "mozilla/dom/RequestBinding.h"
24
25
class nsIGlobalObject;
26
class nsIEventTarget;
27
28
namespace mozilla {
29
namespace dom {
30
31
class BlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString;
32
class BlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrReadableStreamOrUSVString;
33
class BlobImpl;
34
class InternalRequest;
35
class OwningBlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString;
36
struct  ReadableStream;
37
class RequestOrUSVString;
38
class WorkerPrivate;
39
40
enum class CallerType : uint32_t;
41
42
already_AddRefed<Promise>
43
FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
44
             const RequestInit& aInit, CallerType aCallerType,
45
             ErrorResult& aRv);
46
47
nsresult
48
UpdateRequestReferrer(nsIGlobalObject* aGlobal, InternalRequest* aRequest);
49
50
namespace fetch {
51
typedef BlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString BodyInit;
52
typedef BlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrReadableStreamOrUSVString ResponseBodyInit;
53
typedef OwningBlobOrArrayBufferViewOrArrayBufferOrFormDataOrURLSearchParamsOrUSVString OwningBodyInit;
54
};
55
56
/*
57
 * Creates an nsIInputStream based on the fetch specifications 'extract a byte
58
 * stream algorithm' - http://fetch.spec.whatwg.org/#concept-bodyinit-extract.
59
 * Stores content type in out param aContentType.
60
 */
61
nsresult
62
ExtractByteStreamFromBody(const fetch::OwningBodyInit& aBodyInit,
63
                          nsIInputStream** aStream,
64
                          nsCString& aContentType,
65
                          uint64_t& aContentLength);
66
67
/*
68
 * Non-owning version.
69
 */
70
nsresult
71
ExtractByteStreamFromBody(const fetch::BodyInit& aBodyInit,
72
                          nsIInputStream** aStream,
73
                          nsCString& aContentType,
74
                          uint64_t& aContentLength);
75
76
/*
77
 * Non-owning version. This method should go away when BodyInit will contain
78
 * ReadableStream.
79
 */
80
nsresult
81
ExtractByteStreamFromBody(const fetch::ResponseBodyInit& aBodyInit,
82
                          nsIInputStream** aStream,
83
                          nsCString& aContentType,
84
                          uint64_t& aContentLength);
85
86
template <class Derived> class FetchBodyConsumer;
87
88
enum FetchConsumeType
89
{
90
  CONSUME_ARRAYBUFFER,
91
  CONSUME_BLOB,
92
  CONSUME_FORMDATA,
93
  CONSUME_JSON,
94
  CONSUME_TEXT,
95
};
96
97
class FetchStreamHolder
98
{
99
public:
100
  NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING
101
102
  virtual void
103
  NullifyStream() = 0;
104
105
  virtual void
106
  MarkAsRead() = 0;
107
108
  virtual JSObject*
109
  ReadableStreamBody() = 0;
110
};
111
112
/*
113
 * FetchBody's body consumption uses nsIInputStreamPump to read from the
114
 * underlying stream to a block of memory, which is then adopted by
115
 * ContinueConsumeBody() and converted to the right type based on the JS
116
 * function called.
117
 *
118
 * Use of the nsIInputStreamPump complicates things on the worker thread.
119
 * The solution used here is similar to WebSockets.
120
 * The difference is that we are only interested in completion and not data
121
 * events, and nsIInputStreamPump can only deliver completion on the main thread.
122
 *
123
 * Before starting the pump on the main thread, we addref the FetchBody to keep
124
 * it alive. Then we add a feature, to track the status of the worker.
125
 *
126
 * ContinueConsumeBody() is the function that cleans things up in both success
127
 * and error conditions and so all callers call it with the appropriate status.
128
 *
129
 * Once the read is initiated on the main thread there are two possibilities.
130
 *
131
 * 1) Pump finishes before worker has finished Running.
132
 *    In this case we adopt the data and dispatch a runnable to the worker,
133
 *    which derefs FetchBody and removes the feature and resolves the Promise.
134
 *
135
 * 2) Pump still working while worker has stopped Running.
136
 *    The feature is Notify()ed and ContinueConsumeBody() is called with
137
 *    NS_BINDING_ABORTED. We first Cancel() the pump using a sync runnable to
138
 *    ensure that mFetchBody remains alive (since mConsumeBodyPump is strongly
139
 *    held by it) until pump->Cancel() is called. OnStreamComplete() will not
140
 *    do anything if the error code is NS_BINDING_ABORTED, so we don't have to
141
 *    worry about keeping anything alive.
142
 *
143
 * The pump is always released on the main thread.
144
 */
145
template <class Derived>
146
class FetchBody : public FetchStreamHolder
147
                , public AbortFollower
148
{
149
public:
150
  friend class FetchBodyConsumer<Derived>;
151
152
  bool
153
  BodyUsed() const;
154
155
  already_AddRefed<Promise>
156
  ArrayBuffer(JSContext* aCx, ErrorResult& aRv)
157
0
  {
158
0
    return ConsumeBody(aCx, CONSUME_ARRAYBUFFER, aRv);
159
0
  }
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Request>::ArrayBuffer(JSContext*, mozilla::ErrorResult&)
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Response>::ArrayBuffer(JSContext*, mozilla::ErrorResult&)
160
161
  already_AddRefed<Promise>
162
  Blob(JSContext* aCx, ErrorResult& aRv)
163
0
  {
164
0
    return ConsumeBody(aCx, CONSUME_BLOB, aRv);
165
0
  }
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Request>::Blob(JSContext*, mozilla::ErrorResult&)
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Response>::Blob(JSContext*, mozilla::ErrorResult&)
166
167
  already_AddRefed<Promise>
168
  FormData(JSContext* aCx, ErrorResult& aRv)
169
0
  {
170
0
    return ConsumeBody(aCx, CONSUME_FORMDATA, aRv);
171
0
  }
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Request>::FormData(JSContext*, mozilla::ErrorResult&)
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Response>::FormData(JSContext*, mozilla::ErrorResult&)
172
173
  already_AddRefed<Promise>
174
  Json(JSContext* aCx, ErrorResult& aRv)
175
0
  {
176
0
    return ConsumeBody(aCx, CONSUME_JSON, aRv);
177
0
  }
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Request>::Json(JSContext*, mozilla::ErrorResult&)
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Response>::Json(JSContext*, mozilla::ErrorResult&)
178
179
  already_AddRefed<Promise>
180
  Text(JSContext* aCx, ErrorResult& aRv)
181
0
  {
182
0
    return ConsumeBody(aCx, CONSUME_TEXT, aRv);
183
0
  }
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Request>::Text(JSContext*, mozilla::ErrorResult&)
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Response>::Text(JSContext*, mozilla::ErrorResult&)
184
185
  void
186
  GetBody(JSContext* aCx,
187
          JS::MutableHandle<JSObject*> aBodyOut,
188
          ErrorResult& aRv);
189
190
  const nsAString&
191
  BodyLocalPath() const;
192
193
  // If the body contains a ReadableStream body object, this method produces a
194
  // tee() of it.
195
  void
196
  MaybeTeeReadableStreamBody(JSContext* aCx,
197
                             JS::MutableHandle<JSObject*> aBodyOut,
198
                             FetchStreamReader** aStreamReader,
199
                             nsIInputStream** aInputStream,
200
                             ErrorResult& aRv);
201
202
  // Utility public methods accessed by various runnables.
203
204
  // This method _must_ be called in order to set the body as used. If the body
205
  // is a ReadableStream, this method will start reading the stream.
206
  // More in details, this method does:
207
  // 1) It uses an internal flag to track if the body is used.  This is tracked
208
  // separately from the ReadableStream disturbed state due to purely native
209
  // streams.
210
  // 2) If there is a ReadableStream reflector for the native stream it is
211
  // Locked.
212
  // 3) If there is a JS ReadableStream then we begin pumping it into the native
213
  // body stream.  This effectively locks and disturbs the stream.
214
  //
215
  // Note that JSContext is used only if there is a ReadableStream (this can
216
  // happen because the body is a ReadableStream or because attribute body has
217
  // already been used by content). If something goes wrong using
218
  // ReadableStream, errors will be reported via ErrorResult and not as JS
219
  // exceptions in JSContext. This is done in order to have a centralized error
220
  // reporting way.
221
  //
222
  // Exceptions generated when reading from the ReadableStream are directly sent
223
  // to the Console.
224
  void
225
  SetBodyUsed(JSContext* aCx, ErrorResult& aRv);
226
227
  const nsCString&
228
  MimeType() const
229
0
  {
230
0
    return mMimeType;
231
0
  }
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Request>::MimeType() const
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Response>::MimeType() const
232
233
  // FetchStreamHolder
234
  void
235
  NullifyStream() override
236
0
  {
237
0
    mReadableStreamBody = nullptr;
238
0
    mReadableStreamReader = nullptr;
239
0
    mFetchStreamReader = nullptr;
240
0
  }
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Request>::NullifyStream()
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Response>::NullifyStream()
241
242
  JSObject*
243
  ReadableStreamBody() override
244
0
  {
245
0
    MOZ_ASSERT(mReadableStreamBody);
246
0
    return mReadableStreamBody;
247
0
  }
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Request>::ReadableStreamBody()
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Response>::ReadableStreamBody()
248
249
  void
250
  MarkAsRead() override
251
0
  {
252
0
    mBodyUsed = true;
253
0
  }
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Request>::MarkAsRead()
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Response>::MarkAsRead()
254
255
  virtual AbortSignalImpl*
256
  GetSignalImpl() const = 0;
257
258
  // AbortFollower
259
  void
260
  Abort() override;
261
262
protected:
263
  nsCOMPtr<nsIGlobalObject> mOwner;
264
265
  // Always set whenever the FetchBody is created on the worker thread.
266
  WorkerPrivate* mWorkerPrivate;
267
268
  // This is the ReadableStream exposed to content. It's underlying source is a
269
  // FetchStream object.
270
  JS::Heap<JSObject*> mReadableStreamBody;
271
272
  // This is the Reader used to retrieve data from the body.
273
  JS::Heap<JSObject*> mReadableStreamReader;
274
  RefPtr<FetchStreamReader> mFetchStreamReader;
275
276
  explicit FetchBody(nsIGlobalObject* aOwner);
277
278
  virtual ~FetchBody();
279
280
  void
281
  SetMimeType();
282
283
  void
284
  SetReadableStreamBody(JSContext* aCx, JSObject* aBody);
285
286
private:
287
  Derived*
288
  DerivedClass() const
289
0
  {
290
0
    return static_cast<Derived*>(const_cast<FetchBody*>(this));
291
0
  }
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Request>::DerivedClass() const
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Response>::DerivedClass() const
292
293
  already_AddRefed<Promise>
294
  ConsumeBody(JSContext* aCx, FetchConsumeType aType, ErrorResult& aRv);
295
296
  void
297
  LockStream(JSContext* aCx, JS::HandleObject aStream, ErrorResult& aRv);
298
299
  bool
300
  IsOnTargetThread()
301
  {
302
    return NS_IsMainThread() == !mWorkerPrivate;
303
  }
304
305
  void
306
  AssertIsOnTargetThread()
307
  {
308
    MOZ_ASSERT(IsOnTargetThread());
309
  }
310
311
  // Only ever set once, always on target thread.
312
  bool mBodyUsed;
313
  nsCString mMimeType;
314
315
  // The main-thread event target for runnable dispatching.
316
  nsCOMPtr<nsIEventTarget> mMainThreadEventTarget;
317
};
318
319
} // namespace dom
320
} // namespace mozilla
321
322
#endif // mozilla_dom_Fetch_h