Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/fetch/Fetch.cpp
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
#include "Fetch.h"
8
#include "FetchConsumer.h"
9
#include "FetchStream.h"
10
11
#include "nsIDocument.h"
12
#include "nsIGlobalObject.h"
13
#include "nsIStreamLoader.h"
14
15
#include "nsCharSeparatedTokenizer.h"
16
#include "nsDOMString.h"
17
#include "nsJSUtils.h"
18
#include "nsNetUtil.h"
19
#include "nsReadableUtils.h"
20
#include "nsStreamUtils.h"
21
#include "nsStringStream.h"
22
#include "nsProxyRelease.h"
23
24
#include "mozilla/ErrorResult.h"
25
#include "mozilla/dom/BindingDeclarations.h"
26
#include "mozilla/dom/BodyUtil.h"
27
#include "mozilla/dom/Exceptions.h"
28
#include "mozilla/dom/DOMException.h"
29
#include "mozilla/dom/FetchDriver.h"
30
#include "mozilla/dom/File.h"
31
#include "mozilla/dom/FormData.h"
32
#include "mozilla/dom/Headers.h"
33
#include "mozilla/dom/MutableBlobStreamListener.h"
34
#include "mozilla/dom/Promise.h"
35
#include "mozilla/dom/PromiseWorkerProxy.h"
36
#include "mozilla/dom/Request.h"
37
#include "mozilla/dom/Response.h"
38
#include "mozilla/dom/ScriptSettings.h"
39
#include "mozilla/dom/URLSearchParams.h"
40
#include "mozilla/Telemetry.h"
41
42
#include "BodyExtractor.h"
43
#include "FetchObserver.h"
44
#include "InternalRequest.h"
45
#include "InternalResponse.h"
46
47
#include "mozilla/dom/WorkerCommon.h"
48
#include "mozilla/dom/WorkerPrivate.h"
49
#include "mozilla/dom/WorkerRef.h"
50
#include "mozilla/dom/WorkerRunnable.h"
51
#include "mozilla/dom/WorkerScope.h"
52
53
namespace mozilla {
54
namespace dom {
55
56
namespace {
57
58
void
59
AbortStream(JSContext* aCx, JS::Handle<JSObject*> aStream)
60
0
{
61
0
  if (!JS::ReadableStreamIsReadable(aStream)) {
62
0
    return;
63
0
  }
64
0
65
0
  RefPtr<DOMException> e = DOMException::Create(NS_ERROR_DOM_ABORT_ERR);
66
0
67
0
  JS::Rooted<JS::Value> value(aCx);
68
0
  if (!GetOrCreateDOMReflector(aCx, e, &value)) {
69
0
    return;
70
0
  }
71
0
72
0
  JS::ReadableStreamError(aCx, aStream, value);
73
0
}
74
75
} // anonymous
76
77
class AbortSignalMainThread final : public AbortSignalImpl
78
{
79
public:
80
  NS_DECL_CYCLE_COLLECTING_ISUPPORTS
81
  NS_DECL_CYCLE_COLLECTION_CLASS(AbortSignalMainThread)
82
83
  explicit AbortSignalMainThread(bool aAborted)
84
    : AbortSignalImpl(aAborted)
85
0
  {}
86
87
private:
88
  ~AbortSignalMainThread() = default;
89
};
90
91
NS_IMPL_CYCLE_COLLECTION_CLASS(AbortSignalMainThread)
92
93
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AbortSignalMainThread)
94
0
  tmp->Unfollow();
95
0
NS_IMPL_CYCLE_COLLECTION_UNLINK_END
96
97
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AbortSignalMainThread)
98
0
  NS_IMPL_CYCLE_COLLECTION_TRAVERSE(mFollowingSignal)
99
0
NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
100
101
0
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AbortSignalMainThread)
102
0
  NS_INTERFACE_MAP_ENTRY(nsISupports)
103
0
NS_INTERFACE_MAP_END
104
105
NS_IMPL_CYCLE_COLLECTING_ADDREF(AbortSignalMainThread)
106
NS_IMPL_CYCLE_COLLECTING_RELEASE(AbortSignalMainThread)
107
108
// This class helps the proxying of AbortSignalImpl changes cross threads.
109
class AbortSignalProxy final : public AbortFollower
110
{
111
  // This is created and released on the main-thread.
112
  RefPtr<AbortSignalImpl> mSignalImplMainThread;
113
114
  // The main-thread event target for runnable dispatching.
115
  nsCOMPtr<nsIEventTarget> mMainThreadEventTarget;
116
117
  // This value is used only for the creation of AbortSignalImpl on the
118
  // main-thread. They are not updated.
119
  const bool mAborted;
120
121
  // This runnable propagates changes from the AbortSignalImpl on workers to the
122
  // AbortSignalImpl on main-thread.
123
  class AbortSignalProxyRunnable final : public Runnable
124
  {
125
    RefPtr<AbortSignalProxy> mProxy;
126
127
  public:
128
    explicit AbortSignalProxyRunnable(AbortSignalProxy* aProxy)
129
      : Runnable("dom::AbortSignalProxy::AbortSignalProxyRunnable")
130
      , mProxy(aProxy)
131
0
    {}
132
133
    NS_IMETHOD
134
    Run() override
135
0
    {
136
0
      MOZ_ASSERT(NS_IsMainThread());
137
0
      AbortSignalImpl* signalImpl =
138
0
        mProxy->GetOrCreateSignalImplForMainThread();
139
0
      signalImpl->Abort();
140
0
      return NS_OK;
141
0
    }
142
  };
143
144
public:
145
  NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AbortSignalProxy)
146
147
  AbortSignalProxy(AbortSignalImpl* aSignalImpl,
148
                   nsIEventTarget* aMainThreadEventTarget)
149
    : mMainThreadEventTarget(aMainThreadEventTarget)
150
    , mAborted(aSignalImpl->Aborted())
151
0
  {
152
0
    MOZ_ASSERT(mMainThreadEventTarget);
153
0
    Follow(aSignalImpl);
154
0
  }
155
156
  void
157
  Abort() override
158
0
  {
159
0
    RefPtr<AbortSignalProxyRunnable> runnable =
160
0
      new AbortSignalProxyRunnable(this);
161
0
    mMainThreadEventTarget->Dispatch(runnable.forget(), NS_DISPATCH_NORMAL);
162
0
  }
163
164
  AbortSignalImpl*
165
  GetOrCreateSignalImplForMainThread()
166
0
  {
167
0
    MOZ_ASSERT(NS_IsMainThread());
168
0
    if (!mSignalImplMainThread) {
169
0
      mSignalImplMainThread = new AbortSignalMainThread(mAborted);
170
0
    }
171
0
    return mSignalImplMainThread;
172
0
  }
173
174
  AbortSignalImpl*
175
  GetSignalImplForTargetThread()
176
0
  {
177
0
    return mFollowingSignal;
178
0
  }
179
180
  void
181
  Shutdown()
182
0
  {
183
0
    Unfollow();
184
0
  }
185
186
private:
187
  ~AbortSignalProxy()
188
0
  {
189
0
    NS_ProxyRelease(
190
0
      "AbortSignalProxy::mSignalImplMainThread",
191
0
      mMainThreadEventTarget, mSignalImplMainThread.forget());
192
0
  }
193
};
194
195
class WorkerFetchResolver final : public FetchDriverObserver
196
{
197
  // Thread-safe:
198
  RefPtr<PromiseWorkerProxy> mPromiseProxy;
199
  RefPtr<AbortSignalProxy> mSignalProxy;
200
201
  // Touched only on the worker thread.
202
  RefPtr<FetchObserver> mFetchObserver;
203
  RefPtr<WeakWorkerRef> mWorkerRef;
204
205
public:
206
  // Returns null if worker is shutting down.
207
  static already_AddRefed<WorkerFetchResolver>
208
  Create(WorkerPrivate* aWorkerPrivate, Promise* aPromise,
209
         AbortSignalImpl* aSignalImpl, FetchObserver* aObserver)
210
0
  {
211
0
    MOZ_ASSERT(aWorkerPrivate);
212
0
    aWorkerPrivate->AssertIsOnWorkerThread();
213
0
    RefPtr<PromiseWorkerProxy> proxy =
214
0
      PromiseWorkerProxy::Create(aWorkerPrivate, aPromise);
215
0
    if (!proxy) {
216
0
      return nullptr;
217
0
    }
218
0
219
0
    RefPtr<AbortSignalProxy> signalProxy;
220
0
    if (aSignalImpl) {
221
0
      signalProxy =
222
0
        new AbortSignalProxy(aSignalImpl,
223
0
                             aWorkerPrivate->MainThreadEventTarget());
224
0
    }
225
0
226
0
    RefPtr<WorkerFetchResolver> r =
227
0
      new WorkerFetchResolver(proxy, signalProxy, aObserver);
228
0
229
0
    RefPtr<WeakWorkerRef> workerRef =
230
0
      WeakWorkerRef::Create(aWorkerPrivate, [r]() {
231
0
        r->Shutdown(r->mWorkerRef->GetPrivate());
232
0
      });
233
0
    if (NS_WARN_IF(!workerRef)) {
234
0
      return nullptr;
235
0
    }
236
0
237
0
    r->mWorkerRef = std::move(workerRef);
238
0
239
0
    return r.forget();
240
0
  }
241
242
  AbortSignalImpl*
243
  GetAbortSignalForMainThread()
244
0
  {
245
0
    MOZ_ASSERT(NS_IsMainThread());
246
0
247
0
    if (!mSignalProxy) {
248
0
      return nullptr;
249
0
    }
250
0
251
0
    return mSignalProxy->GetOrCreateSignalImplForMainThread();
252
0
  }
253
254
  AbortSignalImpl*
255
  GetAbortSignalForTargetThread()
256
0
  {
257
0
    mPromiseProxy->GetWorkerPrivate()->AssertIsOnWorkerThread();
258
0
259
0
    if (!mSignalProxy) {
260
0
      return nullptr;
261
0
    }
262
0
263
0
    return mSignalProxy->GetSignalImplForTargetThread();
264
0
  }
265
266
  PromiseWorkerProxy*
267
  PromiseProxy() const
268
0
  {
269
0
    MOZ_ASSERT(NS_IsMainThread());
270
0
    return mPromiseProxy;
271
0
  }
272
273
  Promise*
274
  WorkerPromise(WorkerPrivate* aWorkerPrivate) const
275
0
  {
276
0
    MOZ_ASSERT(aWorkerPrivate);
277
0
    aWorkerPrivate->AssertIsOnWorkerThread();
278
0
279
0
    return mPromiseProxy->WorkerPromise();
280
0
  }
281
282
  FetchObserver*
283
  GetFetchObserver(WorkerPrivate* aWorkerPrivate) const
284
0
  {
285
0
    MOZ_ASSERT(aWorkerPrivate);
286
0
    aWorkerPrivate->AssertIsOnWorkerThread();
287
0
288
0
    return mFetchObserver;
289
0
  }
290
291
  void
292
  OnResponseAvailableInternal(InternalResponse* aResponse) override;
293
294
  void
295
  OnResponseEnd(FetchDriverObserver::EndReason eReason) override;
296
297
  bool
298
  NeedOnDataAvailable() override;
299
300
  void
301
  OnDataAvailable() override;
302
303
  void
304
  Shutdown(WorkerPrivate* aWorkerPrivate)
305
0
  {
306
0
    MOZ_ASSERT(aWorkerPrivate);
307
0
    aWorkerPrivate->AssertIsOnWorkerThread();
308
0
309
0
    mPromiseProxy->CleanUp();
310
0
311
0
    mFetchObserver = nullptr;
312
0
313
0
    if (mSignalProxy) {
314
0
      mSignalProxy->Shutdown();
315
0
    }
316
0
317
0
    mWorkerRef = nullptr;
318
0
  }
319
320
private:
321
   WorkerFetchResolver(PromiseWorkerProxy* aProxy,
322
                       AbortSignalProxy* aSignalProxy,
323
                       FetchObserver* aObserver)
324
    : mPromiseProxy(aProxy)
325
    , mSignalProxy(aSignalProxy)
326
    , mFetchObserver(aObserver)
327
0
  {
328
0
    MOZ_ASSERT(!NS_IsMainThread());
329
0
    MOZ_ASSERT(mPromiseProxy);
330
0
  }
331
332
  ~WorkerFetchResolver()
333
0
  {}
334
335
  virtual void
336
  FlushConsoleReport() override;
337
};
338
339
class MainThreadFetchResolver final : public FetchDriverObserver
340
{
341
  RefPtr<Promise> mPromise;
342
  RefPtr<Response> mResponse;
343
  RefPtr<FetchObserver> mFetchObserver;
344
  RefPtr<AbortSignalImpl> mSignalImpl;
345
  const bool mMozErrors;
346
347
  nsCOMPtr<nsILoadGroup> mLoadGroup;
348
349
  NS_DECL_OWNINGTHREAD
350
public:
351
  MainThreadFetchResolver(Promise* aPromise, FetchObserver* aObserver,
352
                          AbortSignalImpl* aSignalImpl, bool aMozErrors)
353
    : mPromise(aPromise)
354
    , mFetchObserver(aObserver)
355
    , mSignalImpl(aSignalImpl)
356
    , mMozErrors(aMozErrors)
357
0
  {}
358
359
  void
360
  OnResponseAvailableInternal(InternalResponse* aResponse) override;
361
362
  void SetLoadGroup(nsILoadGroup* aLoadGroup)
363
0
  {
364
0
    mLoadGroup = aLoadGroup;
365
0
  }
366
367
  void
368
  OnResponseEnd(FetchDriverObserver::EndReason aReason) override
369
0
  {
370
0
    if (aReason == eAborted) {
371
0
      mPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
372
0
    }
373
0
374
0
    mFetchObserver = nullptr;
375
0
376
0
    FlushConsoleReport();
377
0
  }
378
379
  bool
380
  NeedOnDataAvailable() override;
381
382
  void
383
  OnDataAvailable() override;
384
385
private:
386
  ~MainThreadFetchResolver();
387
388
  void FlushConsoleReport() override
389
0
  {
390
0
    mReporter->FlushConsoleReports(mLoadGroup);
391
0
  }
392
};
393
394
class MainThreadFetchRunnable : public Runnable
395
{
396
  RefPtr<WorkerFetchResolver> mResolver;
397
  const ClientInfo mClientInfo;
398
  const Maybe<ServiceWorkerDescriptor> mController;
399
  RefPtr<InternalRequest> mRequest;
400
401
public:
402
  MainThreadFetchRunnable(WorkerFetchResolver* aResolver,
403
                          const ClientInfo& aClientInfo,
404
                          const Maybe<ServiceWorkerDescriptor>& aController,
405
                          InternalRequest* aRequest)
406
    : Runnable("dom::MainThreadFetchRunnable")
407
    , mResolver(aResolver)
408
    , mClientInfo(aClientInfo)
409
    , mController(aController)
410
    , mRequest(aRequest)
411
0
  {
412
0
    MOZ_ASSERT(mResolver);
413
0
  }
414
415
  NS_IMETHOD
416
  Run() override
417
0
  {
418
0
    AssertIsOnMainThread();
419
0
    RefPtr<FetchDriver> fetch;
420
0
    RefPtr<PromiseWorkerProxy> proxy = mResolver->PromiseProxy();
421
0
422
0
    {
423
0
      // Acquire the proxy mutex while getting data from the WorkerPrivate...
424
0
      MutexAutoLock lock(proxy->Lock());
425
0
      if (proxy->CleanedUp()) {
426
0
        NS_WARNING("Aborting Fetch because worker already shut down");
427
0
        return NS_OK;
428
0
      }
429
0
430
0
      WorkerPrivate* workerPrivate = proxy->GetWorkerPrivate();
431
0
      MOZ_ASSERT(workerPrivate);
432
0
      nsCOMPtr<nsIPrincipal> principal = workerPrivate->GetPrincipal();
433
0
      MOZ_ASSERT(principal);
434
0
      nsCOMPtr<nsILoadGroup> loadGroup = workerPrivate->GetLoadGroup();
435
0
      MOZ_ASSERT(loadGroup);
436
0
      // We don't track if a worker is spawned from a tracking script for now,
437
0
      // so pass false as the last argument to FetchDriver().
438
0
      fetch = new FetchDriver(mRequest, principal, loadGroup,
439
0
                              workerPrivate->MainThreadEventTarget(),
440
0
                              workerPrivate->GetPerformanceStorage(),
441
0
                              false);
442
0
      nsAutoCString spec;
443
0
      if (proxy->GetWorkerPrivate()->GetBaseURI()) {
444
0
        proxy->GetWorkerPrivate()->GetBaseURI()->GetAsciiSpec(spec);
445
0
      }
446
0
      fetch->SetWorkerScript(spec);
447
0
448
0
      fetch->SetClientInfo(mClientInfo);
449
0
      fetch->SetController(mController);
450
0
    }
451
0
452
0
    RefPtr<AbortSignalImpl> signalImpl =
453
0
      mResolver->GetAbortSignalForMainThread();
454
0
455
0
    // ...but release it before calling Fetch, because mResolver's callback can
456
0
    // be called synchronously and they want the mutex, too.
457
0
    return fetch->Fetch(signalImpl, mResolver);
458
0
  }
459
};
460
461
already_AddRefed<Promise>
462
FetchRequest(nsIGlobalObject* aGlobal, const RequestOrUSVString& aInput,
463
             const RequestInit& aInit, CallerType aCallerType, ErrorResult& aRv)
464
0
{
465
0
  RefPtr<Promise> p = Promise::Create(aGlobal, aRv);
466
0
  if (NS_WARN_IF(aRv.Failed())) {
467
0
    return nullptr;
468
0
  }
469
0
470
0
  MOZ_ASSERT(aGlobal);
471
0
472
0
  // Double check that we have chrome privileges if the Request's content
473
0
  // policy type has been overridden.
474
0
  MOZ_ASSERT_IF(aInput.IsRequest() &&
475
0
                aInput.GetAsRequest().IsContentPolicyTypeOverridden(),
476
0
                aCallerType == CallerType::System);
477
0
478
0
  AutoJSAPI jsapi;
479
0
  if (!jsapi.Init(aGlobal)) {
480
0
    aRv.Throw(NS_ERROR_NOT_AVAILABLE);
481
0
    return nullptr;
482
0
  }
483
0
484
0
  JSContext* cx = jsapi.cx();
485
0
  JS::Rooted<JSObject*> jsGlobal(cx, aGlobal->GetGlobalJSObject());
486
0
  GlobalObject global(cx, jsGlobal);
487
0
488
0
  RefPtr<Request> request = Request::Constructor(global, aInput, aInit, aRv);
489
0
  if (aRv.Failed()) {
490
0
    return nullptr;
491
0
  }
492
0
493
0
  RefPtr<InternalRequest> r = request->GetInternalRequest();
494
0
  RefPtr<AbortSignalImpl> signalImpl = request->GetSignalImpl();
495
0
496
0
  if (signalImpl && signalImpl->Aborted()) {
497
0
    // Already aborted signal rejects immediately.
498
0
    aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
499
0
    return nullptr;
500
0
  }
501
0
502
0
  RefPtr<FetchObserver> observer;
503
0
  if (aInit.mObserve.WasPassed()) {
504
0
    observer = new FetchObserver(aGlobal, signalImpl);
505
0
    aInit.mObserve.Value().HandleEvent(*observer);
506
0
  }
507
0
508
0
  if (NS_IsMainThread()) {
509
0
    nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
510
0
    nsCOMPtr<nsIDocument> doc;
511
0
    nsCOMPtr<nsILoadGroup> loadGroup;
512
0
    nsIPrincipal* principal;
513
0
    bool isTrackingFetch = false;
514
0
    if (window) {
515
0
      doc = window->GetExtantDoc();
516
0
      if (!doc) {
517
0
        aRv.Throw(NS_ERROR_FAILURE);
518
0
        return nullptr;
519
0
      }
520
0
      principal = doc->NodePrincipal();
521
0
      loadGroup = doc->GetDocumentLoadGroup();
522
0
523
0
      nsAutoCString fileNameString;
524
0
      if (nsJSUtils::GetCallingLocation(cx, fileNameString)) {
525
0
        isTrackingFetch = doc->IsScriptTracking(fileNameString);
526
0
      }
527
0
    } else {
528
0
      principal = aGlobal->PrincipalOrNull();
529
0
      if (NS_WARN_IF(!principal)) {
530
0
        aRv.Throw(NS_ERROR_FAILURE);
531
0
        return nullptr;
532
0
      }
533
0
      nsresult rv = NS_NewLoadGroup(getter_AddRefs(loadGroup), principal);
534
0
      if (NS_WARN_IF(NS_FAILED(rv))) {
535
0
        aRv.Throw(rv);
536
0
        return nullptr;
537
0
      }
538
0
    }
539
0
540
0
    Telemetry::Accumulate(Telemetry::FETCH_IS_MAINTHREAD, 1);
541
0
542
0
    RefPtr<MainThreadFetchResolver> resolver =
543
0
      new MainThreadFetchResolver(p, observer, signalImpl,
544
0
                                  request->MozErrors());
545
0
    RefPtr<FetchDriver> fetch =
546
0
      new FetchDriver(r, principal, loadGroup,
547
0
                      aGlobal->EventTargetFor(TaskCategory::Other),
548
0
                      nullptr, // PerformanceStorage
549
0
                      isTrackingFetch);
550
0
    fetch->SetDocument(doc);
551
0
    resolver->SetLoadGroup(loadGroup);
552
0
    aRv = fetch->Fetch(signalImpl, resolver);
553
0
    if (NS_WARN_IF(aRv.Failed())) {
554
0
      return nullptr;
555
0
    }
556
0
  } else {
557
0
    WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
558
0
    MOZ_ASSERT(worker);
559
0
560
0
    Telemetry::Accumulate(Telemetry::FETCH_IS_MAINTHREAD, 0);
561
0
562
0
    if (worker->IsServiceWorker()) {
563
0
      r->SetSkipServiceWorker();
564
0
    }
565
0
566
0
    RefPtr<WorkerFetchResolver> resolver =
567
0
      WorkerFetchResolver::Create(worker, p, signalImpl, observer);
568
0
    if (!resolver) {
569
0
      NS_WARNING("Could not keep the worker alive.");
570
0
      aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
571
0
      return nullptr;
572
0
    }
573
0
574
0
    Maybe<ClientInfo> clientInfo(worker->GetClientInfo());
575
0
    if (clientInfo.isNothing()) {
576
0
      aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
577
0
      return nullptr;
578
0
    }
579
0
580
0
    RefPtr<MainThreadFetchRunnable> run =
581
0
      new MainThreadFetchRunnable(resolver, clientInfo.ref(),
582
0
                                  worker->GetController(), r);
583
0
    worker->DispatchToMainThread(run.forget());
584
0
  }
585
0
586
0
  return p.forget();
587
0
}
588
589
void
590
MainThreadFetchResolver::OnResponseAvailableInternal(InternalResponse* aResponse)
591
0
{
592
0
  NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver);
593
0
  AssertIsOnMainThread();
594
0
595
0
  if (aResponse->Type() != ResponseType::Error) {
596
0
    if (mFetchObserver) {
597
0
      mFetchObserver->SetState(FetchState::Complete);
598
0
    }
599
0
600
0
    nsCOMPtr<nsIGlobalObject> go = mPromise->GetParentObject();
601
0
    mResponse = new Response(go, aResponse, mSignalImpl);
602
0
    mPromise->MaybeResolve(mResponse);
603
0
  } else {
604
0
    if (mFetchObserver) {
605
0
      mFetchObserver->SetState(FetchState::Errored);
606
0
    }
607
0
608
0
    if (mMozErrors) {
609
0
      mPromise->MaybeReject(aResponse->GetErrorCode());
610
0
      return;
611
0
    }
612
0
613
0
    ErrorResult result;
614
0
    result.ThrowTypeError<MSG_FETCH_FAILED>();
615
0
    mPromise->MaybeReject(result);
616
0
  }
617
0
}
618
619
bool
620
MainThreadFetchResolver::NeedOnDataAvailable()
621
0
{
622
0
  NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver);
623
0
  return !!mFetchObserver;
624
0
}
625
626
void
627
MainThreadFetchResolver::OnDataAvailable()
628
0
{
629
0
  NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver);
630
0
  AssertIsOnMainThread();
631
0
632
0
  if (!mFetchObserver) {
633
0
    return;
634
0
  }
635
0
636
0
  if (mFetchObserver->State() == FetchState::Requesting) {
637
0
    mFetchObserver->SetState(FetchState::Responding);
638
0
  }
639
0
}
640
641
MainThreadFetchResolver::~MainThreadFetchResolver()
642
0
{
643
0
  NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver);
644
0
}
645
646
class WorkerFetchResponseRunnable final : public MainThreadWorkerRunnable
647
{
648
  RefPtr<WorkerFetchResolver> mResolver;
649
  // Passed from main thread to worker thread after being initialized.
650
  RefPtr<InternalResponse> mInternalResponse;
651
public:
652
  WorkerFetchResponseRunnable(WorkerPrivate* aWorkerPrivate,
653
                              WorkerFetchResolver* aResolver,
654
                              InternalResponse* aResponse)
655
    : MainThreadWorkerRunnable(aWorkerPrivate)
656
    , mResolver(aResolver)
657
    , mInternalResponse(aResponse)
658
0
  {
659
0
     MOZ_ASSERT(mResolver);
660
0
  }
661
662
  bool
663
  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
664
0
  {
665
0
    MOZ_ASSERT(aWorkerPrivate);
666
0
    aWorkerPrivate->AssertIsOnWorkerThread();
667
0
668
0
    RefPtr<Promise> promise = mResolver->WorkerPromise(aWorkerPrivate);
669
0
    RefPtr<FetchObserver> fetchObserver =
670
0
      mResolver->GetFetchObserver(aWorkerPrivate);
671
0
672
0
    if (mInternalResponse->Type() != ResponseType::Error) {
673
0
      if (fetchObserver) {
674
0
        fetchObserver->SetState(FetchState::Complete);
675
0
      }
676
0
677
0
      RefPtr<nsIGlobalObject> global = aWorkerPrivate->GlobalScope();
678
0
      RefPtr<Response> response =
679
0
        new Response(global, mInternalResponse,
680
0
                     mResolver->GetAbortSignalForTargetThread());
681
0
      promise->MaybeResolve(response);
682
0
    } else {
683
0
      if (fetchObserver) {
684
0
        fetchObserver->SetState(FetchState::Errored);
685
0
      }
686
0
687
0
      ErrorResult result;
688
0
      result.ThrowTypeError<MSG_FETCH_FAILED>();
689
0
      promise->MaybeReject(result);
690
0
    }
691
0
    return true;
692
0
  }
693
};
694
695
class WorkerDataAvailableRunnable final : public MainThreadWorkerRunnable
696
{
697
  RefPtr<WorkerFetchResolver> mResolver;
698
public:
699
  WorkerDataAvailableRunnable(WorkerPrivate* aWorkerPrivate,
700
                              WorkerFetchResolver* aResolver)
701
    : MainThreadWorkerRunnable(aWorkerPrivate)
702
    , mResolver(aResolver)
703
0
  {
704
0
  }
705
706
  bool
707
  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
708
0
  {
709
0
    MOZ_ASSERT(aWorkerPrivate);
710
0
    aWorkerPrivate->AssertIsOnWorkerThread();
711
0
712
0
    RefPtr<FetchObserver> fetchObserver =
713
0
      mResolver->GetFetchObserver(aWorkerPrivate);
714
0
715
0
    if (fetchObserver &&
716
0
        fetchObserver->State() == FetchState::Requesting) {
717
0
      fetchObserver->SetState(FetchState::Responding);
718
0
    }
719
0
720
0
    return true;
721
0
  }
722
};
723
724
class WorkerFetchResponseEndBase
725
{
726
protected:
727
  RefPtr<WorkerFetchResolver> mResolver;
728
729
public:
730
  explicit WorkerFetchResponseEndBase(WorkerFetchResolver* aResolver)
731
    : mResolver(aResolver)
732
0
  {
733
0
    MOZ_ASSERT(aResolver);
734
0
  }
735
736
  void
737
  WorkerRunInternal(WorkerPrivate* aWorkerPrivate)
738
0
  {
739
0
    mResolver->Shutdown(aWorkerPrivate);
740
0
  }
741
};
742
743
class WorkerFetchResponseEndRunnable final : public MainThreadWorkerRunnable
744
                                           , public WorkerFetchResponseEndBase
745
{
746
  FetchDriverObserver::EndReason mReason;
747
748
public:
749
  WorkerFetchResponseEndRunnable(WorkerPrivate* aWorkerPrivate,
750
                                 WorkerFetchResolver* aResolver,
751
                                 FetchDriverObserver::EndReason aReason)
752
    : MainThreadWorkerRunnable(aWorkerPrivate)
753
    , WorkerFetchResponseEndBase(aResolver)
754
    , mReason(aReason)
755
0
  {
756
0
  }
757
758
  bool
759
  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
760
0
  {
761
0
    if (mReason == FetchDriverObserver::eAborted) {
762
0
      mResolver->WorkerPromise(aWorkerPrivate)->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
763
0
    }
764
0
765
0
    WorkerRunInternal(aWorkerPrivate);
766
0
    return true;
767
0
  }
768
769
  nsresult
770
  Cancel() override
771
0
  {
772
0
    // Execute Run anyway to make sure we cleanup our promise proxy to avoid
773
0
    // leaking the worker thread
774
0
    Run();
775
0
    return WorkerRunnable::Cancel();
776
0
  }
777
};
778
779
class WorkerFetchResponseEndControlRunnable final : public MainThreadWorkerControlRunnable
780
                                                  , public WorkerFetchResponseEndBase
781
{
782
public:
783
  WorkerFetchResponseEndControlRunnable(WorkerPrivate* aWorkerPrivate,
784
                                        WorkerFetchResolver* aResolver)
785
    : MainThreadWorkerControlRunnable(aWorkerPrivate)
786
    , WorkerFetchResponseEndBase(aResolver)
787
0
  {
788
0
  }
789
790
  bool
791
  WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override
792
0
  {
793
0
    WorkerRunInternal(aWorkerPrivate);
794
0
    return true;
795
0
  }
796
797
  // Control runnable cancel already calls Run().
798
};
799
800
void
801
WorkerFetchResolver::OnResponseAvailableInternal(InternalResponse* aResponse)
802
0
{
803
0
  AssertIsOnMainThread();
804
0
805
0
  MutexAutoLock lock(mPromiseProxy->Lock());
806
0
  if (mPromiseProxy->CleanedUp()) {
807
0
    return;
808
0
  }
809
0
810
0
  RefPtr<WorkerFetchResponseRunnable> r =
811
0
    new WorkerFetchResponseRunnable(mPromiseProxy->GetWorkerPrivate(), this,
812
0
                                    aResponse);
813
0
814
0
  if (!r->Dispatch()) {
815
0
    NS_WARNING("Could not dispatch fetch response");
816
0
  }
817
0
}
818
819
bool
820
WorkerFetchResolver::NeedOnDataAvailable()
821
0
{
822
0
  AssertIsOnMainThread();
823
0
  MutexAutoLock lock(mPromiseProxy->Lock());
824
0
  return !!mFetchObserver;
825
0
}
826
827
void
828
WorkerFetchResolver::OnDataAvailable()
829
0
{
830
0
  AssertIsOnMainThread();
831
0
832
0
  MutexAutoLock lock(mPromiseProxy->Lock());
833
0
  if (mPromiseProxy->CleanedUp()) {
834
0
    return;
835
0
  }
836
0
837
0
  RefPtr<WorkerDataAvailableRunnable> r =
838
0
    new WorkerDataAvailableRunnable(mPromiseProxy->GetWorkerPrivate(), this);
839
0
  Unused << r->Dispatch();
840
0
}
841
842
void
843
WorkerFetchResolver::OnResponseEnd(FetchDriverObserver::EndReason aReason)
844
0
{
845
0
  AssertIsOnMainThread();
846
0
  MutexAutoLock lock(mPromiseProxy->Lock());
847
0
  if (mPromiseProxy->CleanedUp()) {
848
0
    return;
849
0
  }
850
0
851
0
  FlushConsoleReport();
852
0
853
0
  RefPtr<WorkerFetchResponseEndRunnable> r =
854
0
    new WorkerFetchResponseEndRunnable(mPromiseProxy->GetWorkerPrivate(),
855
0
                                       this, aReason);
856
0
857
0
  if (!r->Dispatch()) {
858
0
    RefPtr<WorkerFetchResponseEndControlRunnable> cr =
859
0
      new WorkerFetchResponseEndControlRunnable(mPromiseProxy->GetWorkerPrivate(),
860
0
                                                this);
861
0
    // This can fail if the worker thread is canceled or killed causing
862
0
    // the PromiseWorkerProxy to give up its WorkerRef immediately,
863
0
    // allowing the worker thread to become Dead.
864
0
    if (!cr->Dispatch()) {
865
0
      NS_WARNING("Failed to dispatch WorkerFetchResponseEndControlRunnable");
866
0
    }
867
0
  }
868
0
}
869
870
void
871
WorkerFetchResolver::FlushConsoleReport()
872
0
{
873
0
  AssertIsOnMainThread();
874
0
  MOZ_ASSERT(mPromiseProxy);
875
0
876
0
  if(!mReporter) {
877
0
    return;
878
0
  }
879
0
880
0
  WorkerPrivate* worker = mPromiseProxy->GetWorkerPrivate();
881
0
  if (!worker) {
882
0
    mReporter->FlushReportsToConsole(0);
883
0
    return;
884
0
  }
885
0
886
0
  if (worker->IsServiceWorker()) {
887
0
    // Flush to service worker
888
0
    mReporter->FlushReportsToConsoleForServiceWorkerScope(worker->ServiceWorkerScope());
889
0
    return;
890
0
  }
891
0
892
0
  if (worker->IsSharedWorker()) {
893
0
    // Flush to shared worker
894
0
    worker->FlushReportsToSharedWorkers(mReporter);
895
0
    return;
896
0
  }
897
0
898
0
  // Flush to dedicated worker
899
0
  mReporter->FlushConsoleReports(worker->GetLoadGroup());
900
0
}
901
902
nsresult
903
ExtractByteStreamFromBody(const fetch::OwningBodyInit& aBodyInit,
904
                          nsIInputStream** aStream,
905
                          nsCString& aContentTypeWithCharset,
906
                          uint64_t& aContentLength)
907
0
{
908
0
  MOZ_ASSERT(aStream);
909
0
  nsAutoCString charset;
910
0
  aContentTypeWithCharset.SetIsVoid(true);
911
0
912
0
  if (aBodyInit.IsArrayBuffer()) {
913
0
    BodyExtractor<const ArrayBuffer> body(&aBodyInit.GetAsArrayBuffer());
914
0
    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
915
0
                            charset);
916
0
  }
917
0
918
0
  if (aBodyInit.IsArrayBufferView()) {
919
0
    BodyExtractor<const ArrayBufferView> body(&aBodyInit.GetAsArrayBufferView());
920
0
    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
921
0
                            charset);
922
0
  }
923
0
924
0
  if (aBodyInit.IsBlob()) {
925
0
    Blob& blob = aBodyInit.GetAsBlob();
926
0
    BodyExtractor<const Blob> body(&blob);
927
0
    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
928
0
                            charset);
929
0
  }
930
0
931
0
  if (aBodyInit.IsFormData()) {
932
0
    FormData& formData = aBodyInit.GetAsFormData();
933
0
    BodyExtractor<const FormData> body(&formData);
934
0
    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
935
0
                            charset);
936
0
  }
937
0
938
0
  if (aBodyInit.IsUSVString()) {
939
0
    BodyExtractor<const nsAString> body(&aBodyInit.GetAsUSVString());
940
0
    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
941
0
                            charset);
942
0
  }
943
0
944
0
  if (aBodyInit.IsURLSearchParams()) {
945
0
    URLSearchParams& usp = aBodyInit.GetAsURLSearchParams();
946
0
    BodyExtractor<const URLSearchParams> body(&usp);
947
0
    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
948
0
                            charset);
949
0
  }
950
0
951
0
  MOZ_ASSERT_UNREACHABLE("Should never reach here");
952
0
  return NS_ERROR_FAILURE;
953
0
}
954
955
nsresult
956
ExtractByteStreamFromBody(const fetch::BodyInit& aBodyInit,
957
                          nsIInputStream** aStream,
958
                          nsCString& aContentTypeWithCharset,
959
                          uint64_t& aContentLength)
960
0
{
961
0
  MOZ_ASSERT(aStream);
962
0
  MOZ_ASSERT(!*aStream);
963
0
964
0
  nsAutoCString charset;
965
0
  aContentTypeWithCharset.SetIsVoid(true);
966
0
967
0
  if (aBodyInit.IsArrayBuffer()) {
968
0
    BodyExtractor<const ArrayBuffer> body(&aBodyInit.GetAsArrayBuffer());
969
0
    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
970
0
                            charset);
971
0
  }
972
0
973
0
  if (aBodyInit.IsArrayBufferView()) {
974
0
    BodyExtractor<const ArrayBufferView> body(&aBodyInit.GetAsArrayBufferView());
975
0
    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
976
0
                            charset);
977
0
  }
978
0
979
0
  if (aBodyInit.IsBlob()) {
980
0
    BodyExtractor<const Blob> body(&aBodyInit.GetAsBlob());
981
0
    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
982
0
                            charset);
983
0
  }
984
0
985
0
  if (aBodyInit.IsFormData()) {
986
0
    BodyExtractor<const FormData> body(&aBodyInit.GetAsFormData());
987
0
    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
988
0
                            charset);
989
0
  }
990
0
991
0
  if (aBodyInit.IsUSVString()) {
992
0
    BodyExtractor<const nsAString> body(&aBodyInit.GetAsUSVString());
993
0
    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
994
0
                            charset);
995
0
  }
996
0
997
0
  if (aBodyInit.IsURLSearchParams()) {
998
0
    BodyExtractor<const URLSearchParams> body(&aBodyInit.GetAsURLSearchParams());
999
0
    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
1000
0
                            charset);
1001
0
  }
1002
0
1003
0
  MOZ_ASSERT_UNREACHABLE("Should never reach here");
1004
0
  return NS_ERROR_FAILURE;
1005
0
}
1006
1007
nsresult
1008
ExtractByteStreamFromBody(const fetch::ResponseBodyInit& aBodyInit,
1009
                          nsIInputStream** aStream,
1010
                          nsCString& aContentTypeWithCharset,
1011
                          uint64_t& aContentLength)
1012
0
{
1013
0
  MOZ_ASSERT(aStream);
1014
0
  MOZ_ASSERT(!*aStream);
1015
0
1016
0
  // ReadableStreams should be handled by
1017
0
  // BodyExtractorReadableStream::GetAsStream.
1018
0
  MOZ_ASSERT(!aBodyInit.IsReadableStream());
1019
0
1020
0
  nsAutoCString charset;
1021
0
  aContentTypeWithCharset.SetIsVoid(true);
1022
0
1023
0
  if (aBodyInit.IsArrayBuffer()) {
1024
0
    BodyExtractor<const ArrayBuffer> body(&aBodyInit.GetAsArrayBuffer());
1025
0
    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
1026
0
                            charset);
1027
0
  }
1028
0
1029
0
  if (aBodyInit.IsArrayBufferView()) {
1030
0
    BodyExtractor<const ArrayBufferView> body(&aBodyInit.GetAsArrayBufferView());
1031
0
    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
1032
0
                            charset);
1033
0
  }
1034
0
1035
0
  if (aBodyInit.IsBlob()) {
1036
0
    BodyExtractor<const Blob> body(&aBodyInit.GetAsBlob());
1037
0
    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
1038
0
                            charset);
1039
0
  }
1040
0
1041
0
  if (aBodyInit.IsFormData()) {
1042
0
    BodyExtractor<const FormData> body(&aBodyInit.GetAsFormData());
1043
0
    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
1044
0
                            charset);
1045
0
  }
1046
0
1047
0
  if (aBodyInit.IsUSVString()) {
1048
0
    BodyExtractor<const nsAString> body(&aBodyInit.GetAsUSVString());
1049
0
    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
1050
0
                            charset);
1051
0
  }
1052
0
1053
0
  if (aBodyInit.IsURLSearchParams()) {
1054
0
    BodyExtractor<const URLSearchParams> body(&aBodyInit.GetAsURLSearchParams());
1055
0
    return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
1056
0
                            charset);
1057
0
  }
1058
0
1059
0
  MOZ_ASSERT_UNREACHABLE("Should never reach here");
1060
0
  return NS_ERROR_FAILURE;
1061
0
}
1062
1063
template <class Derived>
1064
FetchBody<Derived>::FetchBody(nsIGlobalObject* aOwner)
1065
  : mOwner(aOwner)
1066
  , mWorkerPrivate(nullptr)
1067
  , mReadableStreamBody(nullptr)
1068
  , mReadableStreamReader(nullptr)
1069
  , mBodyUsed(false)
1070
0
{
1071
0
  MOZ_ASSERT(aOwner);
1072
0
1073
0
  if (!NS_IsMainThread()) {
1074
0
    mWorkerPrivate = GetCurrentThreadWorkerPrivate();
1075
0
    MOZ_ASSERT(mWorkerPrivate);
1076
0
    mMainThreadEventTarget = mWorkerPrivate->MainThreadEventTarget();
1077
0
  } else {
1078
0
    mMainThreadEventTarget = aOwner->EventTargetFor(TaskCategory::Other);
1079
0
  }
1080
0
1081
0
  MOZ_ASSERT(mMainThreadEventTarget);
1082
0
}
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Request>::FetchBody(nsIGlobalObject*)
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Response>::FetchBody(nsIGlobalObject*)
1083
1084
template
1085
FetchBody<Request>::FetchBody(nsIGlobalObject* aOwner);
1086
1087
template
1088
FetchBody<Response>::FetchBody(nsIGlobalObject* aOwner);
1089
1090
template <class Derived>
1091
FetchBody<Derived>::~FetchBody()
1092
0
{
1093
0
  Unfollow();
1094
0
}
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Request>::~FetchBody()
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Response>::~FetchBody()
1095
1096
template
1097
FetchBody<Request>::~FetchBody();
1098
1099
template
1100
FetchBody<Response>::~FetchBody();
1101
1102
template <class Derived>
1103
bool
1104
FetchBody<Derived>::BodyUsed() const
1105
0
{
1106
0
  if (mBodyUsed) {
1107
0
    return true;
1108
0
  }
1109
0
1110
0
  // If this object is disturbed or locked, return false.
1111
0
  if (mReadableStreamBody) {
1112
0
    AutoJSAPI jsapi;
1113
0
    if (!jsapi.Init(mOwner)) {
1114
0
      return true;
1115
0
    }
1116
0
1117
0
    JSContext* cx = jsapi.cx();
1118
0
1119
0
    JS::Rooted<JSObject*> body(cx, mReadableStreamBody);
1120
0
    if (JS::ReadableStreamIsDisturbed(body) ||
1121
0
        JS::ReadableStreamIsLocked(body) ||
1122
0
        !JS::ReadableStreamIsReadable(body)) {
1123
0
      return true;
1124
0
    }
1125
0
  }
1126
0
1127
0
  return false;
1128
0
}
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Request>::BodyUsed() const
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Response>::BodyUsed() const
1129
1130
template
1131
bool
1132
FetchBody<Request>::BodyUsed() const;
1133
1134
template
1135
bool
1136
FetchBody<Response>::BodyUsed() const;
1137
1138
template <class Derived>
1139
void
1140
FetchBody<Derived>::SetBodyUsed(JSContext* aCx, ErrorResult& aRv)
1141
0
{
1142
0
  MOZ_ASSERT(aCx);
1143
0
  MOZ_ASSERT(mOwner->EventTargetFor(TaskCategory::Other)->IsOnCurrentThread());
1144
0
1145
0
  if (mBodyUsed) {
1146
0
    return;
1147
0
  }
1148
0
1149
0
  mBodyUsed = true;
1150
0
1151
0
  // If we already have a ReadableStreamBody and it has been created by DOM, we
1152
0
  // have to lock it now because it can have been shared with other objects.
1153
0
  if (mReadableStreamBody) {
1154
0
    JS::Rooted<JSObject*> readableStreamObj(aCx, mReadableStreamBody);
1155
0
    if (JS::ReadableStreamGetMode(readableStreamObj) ==
1156
0
          JS::ReadableStreamMode::ExternalSource) {
1157
0
      LockStream(aCx, readableStreamObj, aRv);
1158
0
      if (NS_WARN_IF(aRv.Failed())) {
1159
0
        return;
1160
0
      }
1161
0
    } else {
1162
0
      // If this is not a native ReadableStream, let's activate the
1163
0
      // FetchStreamReader.
1164
0
      MOZ_ASSERT(mFetchStreamReader);
1165
0
      JS::Rooted<JSObject*> reader(aCx);
1166
0
      mFetchStreamReader->StartConsuming(aCx, readableStreamObj, &reader, aRv);
1167
0
      if (NS_WARN_IF(aRv.Failed())) {
1168
0
        return;
1169
0
      }
1170
0
1171
0
      mReadableStreamReader = reader;
1172
0
    }
1173
0
  }
1174
0
}
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Request>::SetBodyUsed(JSContext*, mozilla::ErrorResult&)
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Response>::SetBodyUsed(JSContext*, mozilla::ErrorResult&)
1175
1176
template
1177
void
1178
FetchBody<Request>::SetBodyUsed(JSContext* aCx, ErrorResult& aRv);
1179
1180
template
1181
void
1182
FetchBody<Response>::SetBodyUsed(JSContext* aCx, ErrorResult& aRv);
1183
1184
template <class Derived>
1185
already_AddRefed<Promise>
1186
FetchBody<Derived>::ConsumeBody(JSContext* aCx, FetchConsumeType aType,
1187
                                ErrorResult& aRv)
1188
0
{
1189
0
  RefPtr<AbortSignalImpl> signalImpl = DerivedClass()->GetSignalImpl();
1190
0
  if (signalImpl && signalImpl->Aborted()) {
1191
0
    aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
1192
0
    return nullptr;
1193
0
  }
1194
0
1195
0
  if (BodyUsed()) {
1196
0
    aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
1197
0
    return nullptr;
1198
0
  }
1199
0
1200
0
  SetBodyUsed(aCx, aRv);
1201
0
  if (NS_WARN_IF(aRv.Failed())) {
1202
0
    return nullptr;
1203
0
  }
1204
0
1205
0
  nsCOMPtr<nsIGlobalObject> global = DerivedClass()->GetParentObject();
1206
0
1207
0
  RefPtr<Promise> promise =
1208
0
    FetchBodyConsumer<Derived>::Create(global, mMainThreadEventTarget, this,
1209
0
                                       signalImpl, aType, aRv);
1210
0
  if (NS_WARN_IF(aRv.Failed())) {
1211
0
    return nullptr;
1212
0
  }
1213
0
1214
0
  return promise.forget();
1215
0
}
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Request>::ConsumeBody(JSContext*, mozilla::dom::FetchConsumeType, mozilla::ErrorResult&)
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Response>::ConsumeBody(JSContext*, mozilla::dom::FetchConsumeType, mozilla::ErrorResult&)
1216
1217
template
1218
already_AddRefed<Promise>
1219
FetchBody<Request>::ConsumeBody(JSContext* aCx, FetchConsumeType aType,
1220
                                ErrorResult& aRv);
1221
1222
template
1223
already_AddRefed<Promise>
1224
FetchBody<Response>::ConsumeBody(JSContext* aCx, FetchConsumeType aType,
1225
                                 ErrorResult& aRv);
1226
1227
template <class Derived>
1228
void
1229
FetchBody<Derived>::SetMimeType()
1230
0
{
1231
0
  // Extract mime type.
1232
0
  ErrorResult result;
1233
0
  nsCString contentTypeValues;
1234
0
  MOZ_ASSERT(DerivedClass()->GetInternalHeaders());
1235
0
  DerivedClass()->GetInternalHeaders()->Get(NS_LITERAL_CSTRING("Content-Type"),
1236
0
                                            contentTypeValues, result);
1237
0
  MOZ_ALWAYS_TRUE(!result.Failed());
1238
0
1239
0
  // HTTP ABNF states Content-Type may have only one value.
1240
0
  // This is from the "parse a header value" of the fetch spec.
1241
0
  if (!contentTypeValues.IsVoid() && contentTypeValues.Find(",") == -1) {
1242
0
    mMimeType = contentTypeValues;
1243
0
    ToLowerCase(mMimeType);
1244
0
  }
1245
0
}
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Request>::SetMimeType()
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Response>::SetMimeType()
1246
1247
template
1248
void
1249
FetchBody<Request>::SetMimeType();
1250
1251
template
1252
void
1253
FetchBody<Response>::SetMimeType();
1254
1255
template <class Derived>
1256
const nsAString&
1257
FetchBody<Derived>::BodyLocalPath() const
1258
0
{
1259
0
  return DerivedClass()->BodyLocalPath();
1260
0
}
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Request>::BodyLocalPath() const
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Response>::BodyLocalPath() const
1261
1262
template
1263
const nsAString&
1264
FetchBody<Request>::BodyLocalPath() const;
1265
1266
template
1267
const nsAString&
1268
FetchBody<Response>::BodyLocalPath() const;
1269
1270
template <class Derived>
1271
void
1272
FetchBody<Derived>::SetReadableStreamBody(JSContext* aCx, JSObject* aBody)
1273
0
{
1274
0
  MOZ_ASSERT(!mReadableStreamBody);
1275
0
  MOZ_ASSERT(aBody);
1276
0
  mReadableStreamBody = aBody;
1277
0
1278
0
  RefPtr<AbortSignalImpl> signalImpl = DerivedClass()->GetSignalImpl();
1279
0
  if (!signalImpl) {
1280
0
    return;
1281
0
  }
1282
0
1283
0
  bool aborted = signalImpl->Aborted();
1284
0
  if (aborted) {
1285
0
    JS::Rooted<JSObject*> body(aCx, mReadableStreamBody);
1286
0
    AbortStream(aCx, body);
1287
0
  } else if (!IsFollowing()) {
1288
0
    Follow(signalImpl);
1289
0
  }
1290
0
}
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Request>::SetReadableStreamBody(JSContext*, JSObject*)
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Response>::SetReadableStreamBody(JSContext*, JSObject*)
1291
1292
template
1293
void
1294
FetchBody<Request>::SetReadableStreamBody(JSContext* aCx, JSObject* aBody);
1295
1296
template
1297
void
1298
FetchBody<Response>::SetReadableStreamBody(JSContext* aCx, JSObject* aBody);
1299
1300
template <class Derived>
1301
void
1302
FetchBody<Derived>::GetBody(JSContext* aCx,
1303
                            JS::MutableHandle<JSObject*> aBodyOut,
1304
                            ErrorResult& aRv)
1305
0
{
1306
0
  if (mReadableStreamBody) {
1307
0
    aBodyOut.set(mReadableStreamBody);
1308
0
    return;
1309
0
  }
1310
0
1311
0
  nsCOMPtr<nsIInputStream> inputStream;
1312
0
  DerivedClass()->GetBody(getter_AddRefs(inputStream));
1313
0
1314
0
  if (!inputStream) {
1315
0
    aBodyOut.set(nullptr);
1316
0
    return;
1317
0
  }
1318
0
1319
0
  JS::Rooted<JSObject*> body(aCx);
1320
0
  FetchStream::Create(aCx, this, DerivedClass()->GetParentObject(),
1321
0
                      inputStream, &body, aRv);
1322
0
  if (NS_WARN_IF(aRv.Failed())) {
1323
0
    return;
1324
0
  }
1325
0
1326
0
  MOZ_ASSERT(body);
1327
0
1328
0
  // If the body has been already consumed, we lock the stream.
1329
0
  if (BodyUsed()) {
1330
0
    LockStream(aCx, body, aRv);
1331
0
    if (NS_WARN_IF(aRv.Failed())) {
1332
0
      return;
1333
0
    }
1334
0
  }
1335
0
1336
0
  RefPtr<AbortSignalImpl> signalImpl = DerivedClass()->GetSignalImpl();
1337
0
  if (signalImpl) {
1338
0
    if (signalImpl->Aborted()) {
1339
0
      AbortStream(aCx, body);
1340
0
    } else if (!IsFollowing()) {
1341
0
      Follow(signalImpl);
1342
0
    }
1343
0
  }
1344
0
1345
0
  mReadableStreamBody = body;
1346
0
  aBodyOut.set(mReadableStreamBody);
1347
0
}
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Request>::GetBody(JSContext*, JS::MutableHandle<JSObject*>, mozilla::ErrorResult&)
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Response>::GetBody(JSContext*, JS::MutableHandle<JSObject*>, mozilla::ErrorResult&)
1348
1349
template
1350
void
1351
FetchBody<Request>::GetBody(JSContext* aCx,
1352
                            JS::MutableHandle<JSObject*> aMessage,
1353
                            ErrorResult& aRv);
1354
1355
template
1356
void
1357
FetchBody<Response>::GetBody(JSContext* aCx,
1358
                             JS::MutableHandle<JSObject*> aMessage,
1359
                             ErrorResult& aRv);
1360
1361
template <class Derived>
1362
void
1363
FetchBody<Derived>::LockStream(JSContext* aCx,
1364
                               JS::HandleObject aStream,
1365
                               ErrorResult& aRv)
1366
0
{
1367
0
  MOZ_ASSERT(JS::ReadableStreamGetMode(aStream) ==
1368
0
               JS::ReadableStreamMode::ExternalSource);
1369
0
1370
0
  // This is native stream, creating a reader will not execute any JS code.
1371
0
  JS::Rooted<JSObject*> reader(aCx,
1372
0
                               JS::ReadableStreamGetReader(aCx, aStream,
1373
0
                                                           JS::ReadableStreamReaderMode::Default));
1374
0
  if (!reader) {
1375
0
    aRv.StealExceptionFromJSContext(aCx);
1376
0
    return;
1377
0
  }
1378
0
1379
0
  mReadableStreamReader = reader;
1380
0
}
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Request>::LockStream(JSContext*, JS::Handle<JSObject*>, mozilla::ErrorResult&)
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Response>::LockStream(JSContext*, JS::Handle<JSObject*>, mozilla::ErrorResult&)
1381
1382
template
1383
void
1384
FetchBody<Request>::LockStream(JSContext* aCx,
1385
                               JS::HandleObject aStream,
1386
                               ErrorResult& aRv);
1387
1388
template
1389
void
1390
FetchBody<Response>::LockStream(JSContext* aCx,
1391
                                JS::HandleObject aStream,
1392
                                ErrorResult& aRv);
1393
1394
template <class Derived>
1395
void
1396
FetchBody<Derived>::MaybeTeeReadableStreamBody(JSContext* aCx,
1397
                                               JS::MutableHandle<JSObject*> aBodyOut,
1398
                                               FetchStreamReader** aStreamReader,
1399
                                               nsIInputStream** aInputStream,
1400
                                               ErrorResult& aRv)
1401
0
{
1402
0
  MOZ_DIAGNOSTIC_ASSERT(aStreamReader);
1403
0
  MOZ_DIAGNOSTIC_ASSERT(aInputStream);
1404
0
  MOZ_DIAGNOSTIC_ASSERT(!BodyUsed());
1405
0
1406
0
  aBodyOut.set(nullptr);
1407
0
  *aStreamReader = nullptr;
1408
0
  *aInputStream = nullptr;
1409
0
1410
0
  if (!mReadableStreamBody) {
1411
0
    return;
1412
0
  }
1413
0
1414
0
  JS::Rooted<JSObject*> stream(aCx, mReadableStreamBody);
1415
0
1416
0
  // If this is a ReadableStream with an external source, this has been
1417
0
  // generated by a Fetch. In this case, Fetch will be able to recreate it
1418
0
  // again when GetBody() is called.
1419
0
  if (JS::ReadableStreamGetMode(stream) == JS::ReadableStreamMode::ExternalSource) {
1420
0
    aBodyOut.set(nullptr);
1421
0
    return;
1422
0
  }
1423
0
1424
0
  JS::Rooted<JSObject*> branch1(aCx);
1425
0
  JS::Rooted<JSObject*> branch2(aCx);
1426
0
1427
0
  if (!JS::ReadableStreamTee(aCx, stream, &branch1, &branch2)) {
1428
0
    aRv.StealExceptionFromJSContext(aCx);
1429
0
    return;
1430
0
  }
1431
0
1432
0
  mReadableStreamBody = branch1;
1433
0
  aBodyOut.set(branch2);
1434
0
1435
0
  aRv = FetchStreamReader::Create(aCx, mOwner, aStreamReader, aInputStream);
1436
0
  if (NS_WARN_IF(aRv.Failed())) {
1437
0
    return;
1438
0
  }
1439
0
}
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Request>::MaybeTeeReadableStreamBody(JSContext*, JS::MutableHandle<JSObject*>, mozilla::dom::FetchStreamReader**, nsIInputStream**, mozilla::ErrorResult&)
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Response>::MaybeTeeReadableStreamBody(JSContext*, JS::MutableHandle<JSObject*>, mozilla::dom::FetchStreamReader**, nsIInputStream**, mozilla::ErrorResult&)
1440
1441
template
1442
void
1443
FetchBody<Request>::MaybeTeeReadableStreamBody(JSContext* aCx,
1444
                                               JS::MutableHandle<JSObject*> aMessage,
1445
                                               FetchStreamReader** aStreamReader,
1446
                                               nsIInputStream** aInputStream,
1447
                                               ErrorResult& aRv);
1448
1449
template
1450
void
1451
FetchBody<Response>::MaybeTeeReadableStreamBody(JSContext* aCx,
1452
                                                JS::MutableHandle<JSObject*> aMessage,
1453
                                                FetchStreamReader** aStreamReader,
1454
                                                nsIInputStream** aInputStream,
1455
                                                ErrorResult& aRv);
1456
1457
template <class Derived>
1458
void
1459
FetchBody<Derived>::Abort()
1460
0
{
1461
0
  if (!mReadableStreamBody) {
1462
0
    return;
1463
0
  }
1464
0
1465
0
  AutoJSAPI jsapi;
1466
0
  if (!jsapi.Init(mOwner)) {
1467
0
    return;
1468
0
  }
1469
0
1470
0
  JSContext* cx = jsapi.cx();
1471
0
1472
0
  JS::Rooted<JSObject*> body(cx, mReadableStreamBody);
1473
0
  AbortStream(cx, body);
1474
0
}
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Request>::Abort()
Unexecuted instantiation: mozilla::dom::FetchBody<mozilla::dom::Response>::Abort()
1475
1476
template
1477
void
1478
FetchBody<Request>::Abort();
1479
1480
template
1481
void
1482
FetchBody<Response>::Abort();
1483
1484
} // namespace dom
1485
} // namespace mozilla