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