Bug 1700051: part 26) Correct typo in comment of `mozInlineSpellWordUtil::BuildSoftTe...
[gecko.git] / dom / fetch / Fetch.cpp
blobe2fb487e9af8e9afb94982b5476fca13fcd3fafe
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/. */
7 #include "Fetch.h"
9 #include "mozilla/dom/Document.h"
10 #include "nsIGlobalObject.h"
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"
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"
38 #include "BodyExtractor.h"
39 #include "EmptyBody.h"
40 #include "FetchObserver.h"
41 #include "InternalRequest.h"
42 #include "InternalResponse.h"
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"
50 namespace mozilla::dom {
52 namespace {
54 void AbortStream(JSContext* aCx, JS::Handle<JSObject*> aStream,
55 ErrorResult& aRv) {
56 aRv.MightThrowJSException();
58 bool isReadable;
59 if (!JS::ReadableStreamIsReadable(aCx, aStream, &isReadable)) {
60 aRv.StealExceptionFromJSContext(aCx);
61 return;
63 if (!isReadable) {
64 return;
67 RefPtr<DOMException> e = DOMException::Create(NS_ERROR_DOM_ABORT_ERR);
69 JS::Rooted<JS::Value> value(aCx);
70 if (!GetOrCreateDOMReflector(aCx, e, &value)) {
71 return;
74 if (!JS::ReadableStreamError(aCx, aStream, value)) {
75 aRv.StealExceptionFromJSContext(aCx);
79 } // namespace
81 class AbortSignalMainThread final : public AbortSignalImpl {
82 public:
83 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
84 NS_DECL_CYCLE_COLLECTION_CLASS(AbortSignalMainThread)
86 explicit AbortSignalMainThread(bool aAborted) : AbortSignalImpl(aAborted) {}
88 private:
89 ~AbortSignalMainThread() = default;
92 NS_IMPL_CYCLE_COLLECTION_CLASS(AbortSignalMainThread)
94 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(AbortSignalMainThread)
95 AbortSignalImpl::Unlink(static_cast<AbortSignalImpl*>(tmp));
96 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
98 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(AbortSignalMainThread)
99 AbortSignalImpl::Traverse(static_cast<AbortSignalImpl*>(tmp), cb);
100 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
102 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(AbortSignalMainThread)
103 NS_INTERFACE_MAP_ENTRY(nsISupports)
104 NS_INTERFACE_MAP_END
106 NS_IMPL_CYCLE_COLLECTING_ADDREF(AbortSignalMainThread)
107 NS_IMPL_CYCLE_COLLECTING_RELEASE(AbortSignalMainThread)
109 class AbortSignalProxy;
111 // An AbortFollower that follows an AbortSignal on a worker thread in order to
112 // propagate signaling abort back to the main thread's AbortSignal.
114 // This class is separate from AbortSignalProxy below so that its refcount is
115 // manipulated only on the worker thread.
116 class WorkerSignalFollower final : public AbortFollower {
117 // This runnable propagates changes from the AbortSignalImpl on workers to the
118 // AbortSignalImpl on main-thread.
119 class AbortSignalProxyRunnable final : public Runnable {
120 RefPtr<AbortSignalProxy> mProxy;
122 public:
123 explicit AbortSignalProxyRunnable(AbortSignalProxy* aProxy)
124 : Runnable("dom::WorkerSignalFollower::AbortSignalProxyRunnable"),
125 mProxy(aProxy) {}
127 NS_IMETHOD Run() override;
130 public:
131 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
132 NS_DECL_CYCLE_COLLECTION_CLASS(WorkerSignalFollower)
134 WorkerSignalFollower(AbortSignalProxy* aProxy, AbortSignalImpl* aSignalImpl)
135 : AbortFollower(), mProxy(aProxy) {
136 MOZ_ASSERT(!NS_IsMainThread());
138 // Follow the worker thread's signal.
139 Follow(aSignalImpl);
142 void RunAbortAlgorithm() override;
144 void Shutdown() {
145 MOZ_ASSERT(!NS_IsMainThread());
146 Unfollow();
147 mProxy = nullptr;
150 private:
151 ~WorkerSignalFollower() = default;
153 RefPtr<AbortSignalProxy> mProxy;
156 NS_IMPL_CYCLE_COLLECTION_CLASS(WorkerSignalFollower)
158 NS_IMPL_CYCLE_COLLECTING_ADDREF(WorkerSignalFollower)
159 NS_IMPL_CYCLE_COLLECTING_RELEASE(WorkerSignalFollower)
161 NS_IMPL_CYCLE_COLLECTION_UNLINK_BEGIN(WorkerSignalFollower)
162 AbortFollower::Unlink(static_cast<AbortFollower*>(tmp));
163 tmp->mProxy = nullptr;
164 NS_IMPL_CYCLE_COLLECTION_UNLINK_END
166 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_BEGIN(WorkerSignalFollower)
167 AbortFollower::Traverse(static_cast<AbortFollower*>(tmp), cb);
168 NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
170 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(WorkerSignalFollower)
171 NS_INTERFACE_MAP_ENTRY(nsISupports)
172 NS_INTERFACE_MAP_END
174 // This class orchestrates the proxying of AbortSignal operations between the
175 // main thread and a worker thread.
176 class AbortSignalProxy final {
177 // An AbortFollower, created/accessed/destroyed only on the worker thread,
178 // that follows the worker-thread AbortSignal and propagates signaling abort
179 // back to the main thread.
181 // mWorkerSignalFollower maintains a cyclic pointer back at this, that is
182 // broken by this->Shutdown() performed on the worker thread. That call is
183 // either performed by WeakWorkerRef if its worker is dropped on the floor, or
184 // at end of the worker fetch response (see
185 // WorkerFetchResponseEndBase::WorkerRunInternal).
186 RefPtr<WorkerSignalFollower> mWorkerSignalFollower;
188 // This is created and released on the main-thread.
189 RefPtr<AbortSignalImpl> mSignalImplMainThread;
191 // The main-thread event target for runnable dispatching.
192 nsCOMPtr<nsIEventTarget> mMainThreadEventTarget;
194 // This value is used only when creating mSignalImplMainThread on the main
195 // thread, to create it in already-aborted state if necessary. It does *not*
196 // reflect the instantaneous is-aborted status of the worker thread's
197 // AbortSignal.
198 const bool mAborted;
200 public:
201 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(AbortSignalProxy)
203 AbortSignalProxy(AbortSignalImpl* aSignalImpl,
204 nsIEventTarget* aMainThreadEventTarget)
205 : mMainThreadEventTarget(aMainThreadEventTarget),
206 mAborted(aSignalImpl->Aborted()) {
207 MOZ_ASSERT(!NS_IsMainThread());
208 MOZ_ASSERT(mMainThreadEventTarget);
210 mWorkerSignalFollower = new WorkerSignalFollower(this, aSignalImpl);
213 AbortSignalImpl* GetOrCreateSignalImplForMainThread() {
214 MOZ_ASSERT(NS_IsMainThread());
215 if (!mSignalImplMainThread) {
216 mSignalImplMainThread = new AbortSignalMainThread(mAborted);
218 return mSignalImplMainThread;
221 AbortSignalImpl* GetSignalImplForTargetThread() {
222 MOZ_ASSERT(!NS_IsMainThread());
223 return mWorkerSignalFollower->Signal();
226 nsIEventTarget* MainThreadEventTarget() { return mMainThreadEventTarget; }
228 void Shutdown() {
229 MOZ_ASSERT(!NS_IsMainThread());
230 mWorkerSignalFollower->Shutdown();
231 mWorkerSignalFollower = nullptr;
234 private:
235 ~AbortSignalProxy() {
236 MOZ_ASSERT(mWorkerSignalFollower == nullptr,
237 "Shutdown() should have been called, on the worker thread, to "
238 "release/free the worker thread's AbortSignal follower by now");
239 NS_ProxyRelease("AbortSignalProxy::mSignalImplMainThread",
240 mMainThreadEventTarget, mSignalImplMainThread.forget());
244 NS_IMETHODIMP WorkerSignalFollower::AbortSignalProxyRunnable::Run() {
245 MOZ_ASSERT(NS_IsMainThread());
246 AbortSignalImpl* signalImpl = mProxy->GetOrCreateSignalImplForMainThread();
247 signalImpl->SignalAbort();
248 return NS_OK;
251 void WorkerSignalFollower::RunAbortAlgorithm() {
252 MOZ_ASSERT(!NS_IsMainThread());
253 RefPtr<AbortSignalProxyRunnable> runnable =
254 new AbortSignalProxyRunnable(mProxy);
255 mProxy->MainThreadEventTarget()->Dispatch(runnable.forget(),
256 NS_DISPATCH_NORMAL);
259 class WorkerFetchResolver final : public FetchDriverObserver {
260 // Thread-safe:
261 RefPtr<PromiseWorkerProxy> mPromiseProxy;
262 RefPtr<AbortSignalProxy> mSignalProxy;
264 // Touched only on the worker thread.
265 RefPtr<FetchObserver> mFetchObserver;
266 RefPtr<WeakWorkerRef> mWorkerRef;
267 bool mIsShutdown;
269 public:
270 // Returns null if worker is shutting down.
271 static already_AddRefed<WorkerFetchResolver> Create(
272 WorkerPrivate* aWorkerPrivate, Promise* aPromise,
273 AbortSignalImpl* aSignalImpl, FetchObserver* aObserver) {
274 MOZ_ASSERT(aWorkerPrivate);
275 aWorkerPrivate->AssertIsOnWorkerThread();
276 RefPtr<PromiseWorkerProxy> proxy =
277 PromiseWorkerProxy::Create(aWorkerPrivate, aPromise);
278 if (!proxy) {
279 return nullptr;
282 RefPtr<AbortSignalProxy> signalProxy;
283 if (aSignalImpl) {
284 signalProxy = new AbortSignalProxy(
285 aSignalImpl, aWorkerPrivate->MainThreadEventTarget());
288 RefPtr<WorkerFetchResolver> r =
289 new WorkerFetchResolver(proxy, signalProxy, aObserver);
291 RefPtr<WeakWorkerRef> workerRef = WeakWorkerRef::Create(
292 aWorkerPrivate, [r]() { r->Shutdown(r->mWorkerRef->GetPrivate()); });
293 if (NS_WARN_IF(!workerRef)) {
294 return nullptr;
297 r->mWorkerRef = std::move(workerRef);
299 return r.forget();
302 AbortSignalImpl* GetAbortSignalForMainThread() {
303 MOZ_ASSERT(NS_IsMainThread());
305 if (!mSignalProxy) {
306 return nullptr;
309 return mSignalProxy->GetOrCreateSignalImplForMainThread();
312 AbortSignalImpl* GetAbortSignalForTargetThread() {
313 mPromiseProxy->GetWorkerPrivate()->AssertIsOnWorkerThread();
315 if (!mSignalProxy) {
316 return nullptr;
319 return mSignalProxy->GetSignalImplForTargetThread();
322 PromiseWorkerProxy* PromiseProxy() const {
323 MOZ_ASSERT(NS_IsMainThread());
324 return mPromiseProxy;
327 Promise* WorkerPromise(WorkerPrivate* aWorkerPrivate) const {
328 MOZ_ASSERT(aWorkerPrivate);
329 aWorkerPrivate->AssertIsOnWorkerThread();
330 MOZ_ASSERT(!mIsShutdown);
332 return mPromiseProxy->WorkerPromise();
335 FetchObserver* GetFetchObserver(WorkerPrivate* aWorkerPrivate) const {
336 MOZ_ASSERT(aWorkerPrivate);
337 aWorkerPrivate->AssertIsOnWorkerThread();
339 return mFetchObserver;
342 void OnResponseAvailableInternal(InternalResponse* aResponse) override;
344 void OnResponseEnd(FetchDriverObserver::EndReason eReason) override;
346 bool NeedOnDataAvailable() override;
348 void OnDataAvailable() override;
350 void Shutdown(WorkerPrivate* aWorkerPrivate) {
351 MOZ_ASSERT(aWorkerPrivate);
352 aWorkerPrivate->AssertIsOnWorkerThread();
354 mIsShutdown = true;
355 mPromiseProxy->CleanUp();
357 mFetchObserver = nullptr;
359 if (mSignalProxy) {
360 mSignalProxy->Shutdown();
361 mSignalProxy = nullptr;
364 mWorkerRef = nullptr;
367 bool IsShutdown(WorkerPrivate* aWorkerPrivate) const {
368 MOZ_ASSERT(aWorkerPrivate);
369 aWorkerPrivate->AssertIsOnWorkerThread();
370 return mIsShutdown;
373 private:
374 WorkerFetchResolver(PromiseWorkerProxy* aProxy,
375 AbortSignalProxy* aSignalProxy, FetchObserver* aObserver)
376 : mPromiseProxy(aProxy),
377 mSignalProxy(aSignalProxy),
378 mFetchObserver(aObserver),
379 mIsShutdown(false) {
380 MOZ_ASSERT(!NS_IsMainThread());
381 MOZ_ASSERT(mPromiseProxy);
384 ~WorkerFetchResolver() = default;
386 virtual void FlushConsoleReport() override;
389 class MainThreadFetchResolver final : public FetchDriverObserver {
390 RefPtr<Promise> mPromise;
391 RefPtr<Response> mResponse;
392 RefPtr<FetchObserver> mFetchObserver;
393 RefPtr<AbortSignalImpl> mSignalImpl;
394 const bool mMozErrors;
396 nsCOMPtr<nsILoadGroup> mLoadGroup;
398 NS_DECL_OWNINGTHREAD
399 public:
400 MainThreadFetchResolver(Promise* aPromise, FetchObserver* aObserver,
401 AbortSignalImpl* aSignalImpl, bool aMozErrors)
402 : mPromise(aPromise),
403 mFetchObserver(aObserver),
404 mSignalImpl(aSignalImpl),
405 mMozErrors(aMozErrors) {}
407 void OnResponseAvailableInternal(InternalResponse* aResponse) override;
409 void SetLoadGroup(nsILoadGroup* aLoadGroup) { mLoadGroup = aLoadGroup; }
411 void OnResponseEnd(FetchDriverObserver::EndReason aReason) override {
412 if (aReason == eAborted) {
413 mPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
416 mFetchObserver = nullptr;
418 FlushConsoleReport();
421 bool NeedOnDataAvailable() override;
423 void OnDataAvailable() override;
425 private:
426 ~MainThreadFetchResolver();
428 void FlushConsoleReport() override {
429 mReporter->FlushConsoleReports(mLoadGroup);
433 class MainThreadFetchRunnable : public Runnable {
434 RefPtr<WorkerFetchResolver> mResolver;
435 const ClientInfo mClientInfo;
436 const Maybe<ServiceWorkerDescriptor> mController;
437 nsCOMPtr<nsICSPEventListener> mCSPEventListener;
438 SafeRefPtr<InternalRequest> mRequest;
439 UniquePtr<SerializedStackHolder> mOriginStack;
441 public:
442 MainThreadFetchRunnable(WorkerFetchResolver* aResolver,
443 const ClientInfo& aClientInfo,
444 const Maybe<ServiceWorkerDescriptor>& aController,
445 nsICSPEventListener* aCSPEventListener,
446 SafeRefPtr<InternalRequest> aRequest,
447 UniquePtr<SerializedStackHolder>&& aOriginStack)
448 : Runnable("dom::MainThreadFetchRunnable"),
449 mResolver(aResolver),
450 mClientInfo(aClientInfo),
451 mController(aController),
452 mCSPEventListener(aCSPEventListener),
453 mRequest(std::move(aRequest)),
454 mOriginStack(std::move(aOriginStack)) {
455 MOZ_ASSERT(mResolver);
458 NS_IMETHOD
459 Run() override {
460 AssertIsOnMainThread();
461 RefPtr<FetchDriver> fetch;
462 RefPtr<PromiseWorkerProxy> proxy = mResolver->PromiseProxy();
465 // Acquire the proxy mutex while getting data from the WorkerPrivate...
466 MutexAutoLock lock(proxy->Lock());
467 if (proxy->CleanedUp()) {
468 NS_WARNING("Aborting Fetch because worker already shut down");
469 return NS_OK;
472 WorkerPrivate* workerPrivate = proxy->GetWorkerPrivate();
473 MOZ_ASSERT(workerPrivate);
474 nsCOMPtr<nsIPrincipal> principal = workerPrivate->GetPrincipal();
475 MOZ_ASSERT(principal);
476 nsCOMPtr<nsILoadGroup> loadGroup = workerPrivate->GetLoadGroup();
477 MOZ_ASSERT(loadGroup);
478 // We don't track if a worker is spawned from a tracking script for now,
479 // so pass false as the last argument to FetchDriver().
480 fetch = new FetchDriver(mRequest.clonePtr(), principal, loadGroup,
481 workerPrivate->MainThreadEventTarget(),
482 workerPrivate->CookieJarSettings(),
483 workerPrivate->GetPerformanceStorage(), false);
484 nsAutoCString spec;
485 if (proxy->GetWorkerPrivate()->GetBaseURI()) {
486 proxy->GetWorkerPrivate()->GetBaseURI()->GetAsciiSpec(spec);
488 fetch->SetWorkerScript(spec);
490 fetch->SetClientInfo(mClientInfo);
491 fetch->SetController(mController);
492 fetch->SetCSPEventListener(mCSPEventListener);
495 fetch->SetOriginStack(std::move(mOriginStack));
497 RefPtr<AbortSignalImpl> signalImpl =
498 mResolver->GetAbortSignalForMainThread();
500 // ...but release it before calling Fetch, because mResolver's callback can
501 // be called synchronously and they want the mutex, too.
502 return fetch->Fetch(signalImpl, mResolver);
506 already_AddRefed<Promise> FetchRequest(nsIGlobalObject* aGlobal,
507 const RequestOrUSVString& aInput,
508 const RequestInit& aInit,
509 CallerType aCallerType,
510 ErrorResult& aRv) {
511 RefPtr<Promise> p = Promise::Create(aGlobal, aRv);
512 if (NS_WARN_IF(aRv.Failed())) {
513 return nullptr;
516 MOZ_ASSERT(aGlobal);
518 // Double check that we have chrome privileges if the Request's content
519 // policy type has been overridden.
520 MOZ_ASSERT_IF(aInput.IsRequest() &&
521 aInput.GetAsRequest().IsContentPolicyTypeOverridden(),
522 aCallerType == CallerType::System);
524 AutoJSAPI jsapi;
525 if (!jsapi.Init(aGlobal)) {
526 aRv.Throw(NS_ERROR_NOT_AVAILABLE);
527 return nullptr;
530 JSContext* cx = jsapi.cx();
531 JS::Rooted<JSObject*> jsGlobal(cx, aGlobal->GetGlobalJSObject());
532 GlobalObject global(cx, jsGlobal);
534 SafeRefPtr<Request> request =
535 Request::Constructor(global, aInput, aInit, aRv);
536 if (aRv.Failed()) {
537 return nullptr;
540 SafeRefPtr<InternalRequest> r = request->GetInternalRequest();
541 RefPtr<AbortSignalImpl> signalImpl = request->GetSignalImpl();
543 if (signalImpl && signalImpl->Aborted()) {
544 // Already aborted signal rejects immediately.
545 aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
546 return nullptr;
549 RefPtr<FetchObserver> observer;
550 if (aInit.mObserve.WasPassed()) {
551 observer = new FetchObserver(aGlobal, signalImpl);
552 aInit.mObserve.Value().HandleEvent(*observer);
555 if (NS_IsMainThread()) {
556 nsCOMPtr<nsPIDOMWindowInner> window = do_QueryInterface(aGlobal);
557 nsCOMPtr<Document> doc;
558 nsCOMPtr<nsILoadGroup> loadGroup;
559 nsCOMPtr<nsICookieJarSettings> cookieJarSettings;
560 nsIPrincipal* principal;
561 bool isTrackingFetch = false;
562 if (window) {
563 doc = window->GetExtantDoc();
564 if (!doc) {
565 aRv.Throw(NS_ERROR_FAILURE);
566 return nullptr;
568 principal = doc->NodePrincipal();
569 loadGroup = doc->GetDocumentLoadGroup();
570 cookieJarSettings = doc->CookieJarSettings();
572 isTrackingFetch = doc->IsScriptTracking(cx);
573 } else {
574 principal = aGlobal->PrincipalOrNull();
575 if (NS_WARN_IF(!principal)) {
576 aRv.Throw(NS_ERROR_FAILURE);
577 return nullptr;
580 cookieJarSettings = mozilla::net::CookieJarSettings::Create(principal);
583 if (!loadGroup) {
584 nsresult rv = NS_NewLoadGroup(getter_AddRefs(loadGroup), principal);
585 if (NS_WARN_IF(NS_FAILED(rv))) {
586 aRv.Throw(rv);
587 return nullptr;
591 RefPtr<MainThreadFetchResolver> resolver = new MainThreadFetchResolver(
592 p, observer, signalImpl, request->MozErrors());
593 RefPtr<FetchDriver> fetch =
594 new FetchDriver(std::move(r), principal, loadGroup,
595 aGlobal->EventTargetFor(TaskCategory::Other),
596 cookieJarSettings, nullptr, // PerformanceStorage
597 isTrackingFetch);
598 fetch->SetDocument(doc);
599 resolver->SetLoadGroup(loadGroup);
600 aRv = fetch->Fetch(signalImpl, resolver);
601 if (NS_WARN_IF(aRv.Failed())) {
602 return nullptr;
604 } else {
605 WorkerPrivate* worker = GetCurrentThreadWorkerPrivate();
606 MOZ_ASSERT(worker);
608 if (worker->IsServiceWorker()) {
609 r->SetSkipServiceWorker();
612 RefPtr<WorkerFetchResolver> resolver =
613 WorkerFetchResolver::Create(worker, p, signalImpl, observer);
614 if (!resolver) {
615 NS_WARNING("Could not keep the worker alive.");
616 aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
617 return nullptr;
620 Maybe<ClientInfo> clientInfo(worker->GlobalScope()->GetClientInfo());
621 if (clientInfo.isNothing()) {
622 aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
623 return nullptr;
626 UniquePtr<SerializedStackHolder> stack;
627 if (worker->IsWatchedByDevTools()) {
628 stack = GetCurrentStackForNetMonitor(cx);
631 RefPtr<MainThreadFetchRunnable> run = new MainThreadFetchRunnable(
632 resolver, clientInfo.ref(), worker->GlobalScope()->GetController(),
633 worker->CSPEventListener(), std::move(r), std::move(stack));
634 worker->DispatchToMainThread(run.forget());
637 return p.forget();
640 class ResolveFetchPromise : public Runnable {
641 public:
642 ResolveFetchPromise(Promise* aPromise, Response* aResponse)
643 : Runnable("ResolveFetchPromise"),
644 mPromise(aPromise),
645 mResponse(aResponse) {}
647 NS_IMETHOD Run() {
648 mPromise->MaybeResolve(mResponse);
649 return NS_OK;
651 RefPtr<Promise> mPromise;
652 RefPtr<Response> mResponse;
655 void MainThreadFetchResolver::OnResponseAvailableInternal(
656 InternalResponse* aResponse) {
657 NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver);
658 AssertIsOnMainThread();
660 if (aResponse->Type() != ResponseType::Error) {
661 nsCOMPtr<nsIGlobalObject> go = mPromise->GetParentObject();
662 nsCOMPtr<nsPIDOMWindowInner> inner = do_QueryInterface(go);
664 // Notify the document when a fetch completes successfully. This is
665 // used by the password manager as a hint to observe DOM mutations.
666 // Call this prior to setting state to Complete so we can set up the
667 // observer before mutations occurs.
668 Document* doc = inner ? inner->GetExtantDoc() : nullptr;
669 if (doc) {
670 doc->NotifyFetchOrXHRSuccess();
673 if (mFetchObserver) {
674 mFetchObserver->SetState(FetchState::Complete);
677 mResponse = new Response(go, aResponse, mSignalImpl);
678 BrowsingContext* bc = inner ? inner->GetBrowsingContext() : nullptr;
679 bc = bc ? bc->Top() : nullptr;
680 if (bc && bc->IsLoading()) {
681 bc->AddDeprioritizedLoadRunner(
682 new ResolveFetchPromise(mPromise, mResponse));
683 } else {
684 mPromise->MaybeResolve(mResponse);
686 } else {
687 if (mFetchObserver) {
688 mFetchObserver->SetState(FetchState::Errored);
691 if (mMozErrors) {
692 mPromise->MaybeReject(aResponse->GetErrorCode());
693 return;
696 mPromise->MaybeRejectWithTypeError<MSG_FETCH_FAILED>();
700 bool MainThreadFetchResolver::NeedOnDataAvailable() {
701 NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver);
702 return !!mFetchObserver;
705 void MainThreadFetchResolver::OnDataAvailable() {
706 NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver);
707 AssertIsOnMainThread();
709 if (!mFetchObserver) {
710 return;
713 if (mFetchObserver->State() == FetchState::Requesting) {
714 mFetchObserver->SetState(FetchState::Responding);
718 MainThreadFetchResolver::~MainThreadFetchResolver() {
719 NS_ASSERT_OWNINGTHREAD(MainThreadFetchResolver);
722 class WorkerFetchResponseRunnable final : public MainThreadWorkerRunnable {
723 RefPtr<WorkerFetchResolver> mResolver;
724 // Passed from main thread to worker thread after being initialized.
725 RefPtr<InternalResponse> mInternalResponse;
727 public:
728 WorkerFetchResponseRunnable(WorkerPrivate* aWorkerPrivate,
729 WorkerFetchResolver* aResolver,
730 InternalResponse* aResponse)
731 : MainThreadWorkerRunnable(aWorkerPrivate),
732 mResolver(aResolver),
733 mInternalResponse(aResponse) {
734 MOZ_ASSERT(mResolver);
737 bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
738 MOZ_ASSERT(aWorkerPrivate);
739 aWorkerPrivate->AssertIsOnWorkerThread();
741 RefPtr<Promise> promise = mResolver->WorkerPromise(aWorkerPrivate);
742 RefPtr<FetchObserver> fetchObserver =
743 mResolver->GetFetchObserver(aWorkerPrivate);
745 if (mInternalResponse->Type() != ResponseType::Error) {
746 if (fetchObserver) {
747 fetchObserver->SetState(FetchState::Complete);
750 RefPtr<nsIGlobalObject> global = aWorkerPrivate->GlobalScope();
751 RefPtr<Response> response =
752 new Response(global, mInternalResponse,
753 mResolver->GetAbortSignalForTargetThread());
754 promise->MaybeResolve(response);
755 } else {
756 if (fetchObserver) {
757 fetchObserver->SetState(FetchState::Errored);
760 promise->MaybeRejectWithTypeError<MSG_FETCH_FAILED>();
762 return true;
766 class WorkerDataAvailableRunnable final : public MainThreadWorkerRunnable {
767 RefPtr<WorkerFetchResolver> mResolver;
769 public:
770 WorkerDataAvailableRunnable(WorkerPrivate* aWorkerPrivate,
771 WorkerFetchResolver* aResolver)
772 : MainThreadWorkerRunnable(aWorkerPrivate), mResolver(aResolver) {}
774 bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
775 MOZ_ASSERT(aWorkerPrivate);
776 aWorkerPrivate->AssertIsOnWorkerThread();
778 RefPtr<FetchObserver> fetchObserver =
779 mResolver->GetFetchObserver(aWorkerPrivate);
781 if (fetchObserver && fetchObserver->State() == FetchState::Requesting) {
782 fetchObserver->SetState(FetchState::Responding);
785 return true;
789 class WorkerFetchResponseEndBase {
790 protected:
791 RefPtr<WorkerFetchResolver> mResolver;
793 public:
794 explicit WorkerFetchResponseEndBase(WorkerFetchResolver* aResolver)
795 : mResolver(aResolver) {
796 MOZ_ASSERT(aResolver);
799 void WorkerRunInternal(WorkerPrivate* aWorkerPrivate) {
800 mResolver->Shutdown(aWorkerPrivate);
804 class WorkerFetchResponseEndRunnable final : public MainThreadWorkerRunnable,
805 public WorkerFetchResponseEndBase {
806 FetchDriverObserver::EndReason mReason;
808 public:
809 WorkerFetchResponseEndRunnable(WorkerPrivate* aWorkerPrivate,
810 WorkerFetchResolver* aResolver,
811 FetchDriverObserver::EndReason aReason)
812 : MainThreadWorkerRunnable(aWorkerPrivate),
813 WorkerFetchResponseEndBase(aResolver),
814 mReason(aReason) {}
816 bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
817 if (mResolver->IsShutdown(aWorkerPrivate)) {
818 return true;
821 if (mReason == FetchDriverObserver::eAborted) {
822 mResolver->WorkerPromise(aWorkerPrivate)
823 ->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
826 WorkerRunInternal(aWorkerPrivate);
827 return true;
830 nsresult Cancel() override {
831 // Execute Run anyway to make sure we cleanup our promise proxy to avoid
832 // leaking the worker thread
833 Run();
834 return WorkerRunnable::Cancel();
838 class WorkerFetchResponseEndControlRunnable final
839 : public MainThreadWorkerControlRunnable,
840 public WorkerFetchResponseEndBase {
841 public:
842 WorkerFetchResponseEndControlRunnable(WorkerPrivate* aWorkerPrivate,
843 WorkerFetchResolver* aResolver)
844 : MainThreadWorkerControlRunnable(aWorkerPrivate),
845 WorkerFetchResponseEndBase(aResolver) {}
847 bool WorkerRun(JSContext* aCx, WorkerPrivate* aWorkerPrivate) override {
848 WorkerRunInternal(aWorkerPrivate);
849 return true;
852 // Control runnable cancel already calls Run().
855 void WorkerFetchResolver::OnResponseAvailableInternal(
856 InternalResponse* aResponse) {
857 AssertIsOnMainThread();
859 MutexAutoLock lock(mPromiseProxy->Lock());
860 if (mPromiseProxy->CleanedUp()) {
861 return;
864 RefPtr<WorkerFetchResponseRunnable> r = new WorkerFetchResponseRunnable(
865 mPromiseProxy->GetWorkerPrivate(), this, aResponse);
867 if (!r->Dispatch()) {
868 NS_WARNING("Could not dispatch fetch response");
872 bool WorkerFetchResolver::NeedOnDataAvailable() {
873 AssertIsOnMainThread();
874 MutexAutoLock lock(mPromiseProxy->Lock());
875 return !!mFetchObserver;
878 void WorkerFetchResolver::OnDataAvailable() {
879 AssertIsOnMainThread();
881 MutexAutoLock lock(mPromiseProxy->Lock());
882 if (mPromiseProxy->CleanedUp()) {
883 return;
886 RefPtr<WorkerDataAvailableRunnable> r =
887 new WorkerDataAvailableRunnable(mPromiseProxy->GetWorkerPrivate(), this);
888 Unused << r->Dispatch();
891 void WorkerFetchResolver::OnResponseEnd(
892 FetchDriverObserver::EndReason aReason) {
893 AssertIsOnMainThread();
894 MutexAutoLock lock(mPromiseProxy->Lock());
895 if (mPromiseProxy->CleanedUp()) {
896 return;
899 FlushConsoleReport();
901 RefPtr<WorkerFetchResponseEndRunnable> r = new WorkerFetchResponseEndRunnable(
902 mPromiseProxy->GetWorkerPrivate(), this, aReason);
904 if (!r->Dispatch()) {
905 RefPtr<WorkerFetchResponseEndControlRunnable> cr =
906 new WorkerFetchResponseEndControlRunnable(
907 mPromiseProxy->GetWorkerPrivate(), this);
908 // This can fail if the worker thread is canceled or killed causing
909 // the PromiseWorkerProxy to give up its WorkerRef immediately,
910 // allowing the worker thread to become Dead.
911 if (!cr->Dispatch()) {
912 NS_WARNING("Failed to dispatch WorkerFetchResponseEndControlRunnable");
917 void WorkerFetchResolver::FlushConsoleReport() {
918 AssertIsOnMainThread();
919 MOZ_ASSERT(mPromiseProxy);
921 if (!mReporter) {
922 return;
925 WorkerPrivate* worker = mPromiseProxy->GetWorkerPrivate();
926 if (!worker) {
927 mReporter->FlushReportsToConsole(0);
928 return;
931 if (worker->IsServiceWorker()) {
932 // Flush to service worker
933 mReporter->FlushReportsToConsoleForServiceWorkerScope(
934 worker->ServiceWorkerScope());
935 return;
938 if (worker->IsSharedWorker()) {
939 // Flush to shared worker
940 worker->GetRemoteWorkerController()->FlushReportsOnMainThread(mReporter);
941 return;
944 // Flush to dedicated worker
945 mReporter->FlushConsoleReports(worker->GetLoadGroup());
948 nsresult ExtractByteStreamFromBody(const fetch::OwningBodyInit& aBodyInit,
949 nsIInputStream** aStream,
950 nsCString& aContentTypeWithCharset,
951 uint64_t& aContentLength) {
952 MOZ_ASSERT(aStream);
953 nsAutoCString charset;
954 aContentTypeWithCharset.SetIsVoid(true);
956 if (aBodyInit.IsArrayBuffer()) {
957 BodyExtractor<const ArrayBuffer> body(&aBodyInit.GetAsArrayBuffer());
958 return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
959 charset);
962 if (aBodyInit.IsArrayBufferView()) {
963 BodyExtractor<const ArrayBufferView> body(
964 &aBodyInit.GetAsArrayBufferView());
965 return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
966 charset);
969 if (aBodyInit.IsBlob()) {
970 Blob& blob = aBodyInit.GetAsBlob();
971 BodyExtractor<const Blob> body(&blob);
972 return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
973 charset);
976 if (aBodyInit.IsFormData()) {
977 FormData& formData = aBodyInit.GetAsFormData();
978 BodyExtractor<const FormData> body(&formData);
979 return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
980 charset);
983 if (aBodyInit.IsUSVString()) {
984 BodyExtractor<const nsAString> body(&aBodyInit.GetAsUSVString());
985 return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
986 charset);
989 if (aBodyInit.IsURLSearchParams()) {
990 URLSearchParams& usp = aBodyInit.GetAsURLSearchParams();
991 BodyExtractor<const URLSearchParams> body(&usp);
992 return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
993 charset);
996 MOZ_ASSERT_UNREACHABLE("Should never reach here");
997 return NS_ERROR_FAILURE;
1000 nsresult ExtractByteStreamFromBody(const fetch::BodyInit& aBodyInit,
1001 nsIInputStream** aStream,
1002 nsCString& aContentTypeWithCharset,
1003 uint64_t& aContentLength) {
1004 MOZ_ASSERT(aStream);
1005 MOZ_ASSERT(!*aStream);
1007 nsAutoCString charset;
1008 aContentTypeWithCharset.SetIsVoid(true);
1010 if (aBodyInit.IsArrayBuffer()) {
1011 BodyExtractor<const ArrayBuffer> body(&aBodyInit.GetAsArrayBuffer());
1012 return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
1013 charset);
1016 if (aBodyInit.IsArrayBufferView()) {
1017 BodyExtractor<const ArrayBufferView> body(
1018 &aBodyInit.GetAsArrayBufferView());
1019 return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
1020 charset);
1023 if (aBodyInit.IsBlob()) {
1024 BodyExtractor<const Blob> body(&aBodyInit.GetAsBlob());
1025 return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
1026 charset);
1029 if (aBodyInit.IsFormData()) {
1030 BodyExtractor<const FormData> body(&aBodyInit.GetAsFormData());
1031 return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
1032 charset);
1035 if (aBodyInit.IsUSVString()) {
1036 BodyExtractor<const nsAString> body(&aBodyInit.GetAsUSVString());
1037 return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
1038 charset);
1041 if (aBodyInit.IsURLSearchParams()) {
1042 BodyExtractor<const URLSearchParams> body(
1043 &aBodyInit.GetAsURLSearchParams());
1044 return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
1045 charset);
1048 MOZ_ASSERT_UNREACHABLE("Should never reach here");
1049 return NS_ERROR_FAILURE;
1052 nsresult ExtractByteStreamFromBody(const fetch::ResponseBodyInit& aBodyInit,
1053 nsIInputStream** aStream,
1054 nsCString& aContentTypeWithCharset,
1055 uint64_t& aContentLength) {
1056 MOZ_ASSERT(aStream);
1057 MOZ_ASSERT(!*aStream);
1059 // ReadableStreams should be handled by
1060 // BodyExtractorReadableStream::GetAsStream.
1061 MOZ_ASSERT(!aBodyInit.IsReadableStream());
1063 nsAutoCString charset;
1064 aContentTypeWithCharset.SetIsVoid(true);
1066 if (aBodyInit.IsArrayBuffer()) {
1067 BodyExtractor<const ArrayBuffer> body(&aBodyInit.GetAsArrayBuffer());
1068 return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
1069 charset);
1072 if (aBodyInit.IsArrayBufferView()) {
1073 BodyExtractor<const ArrayBufferView> body(
1074 &aBodyInit.GetAsArrayBufferView());
1075 return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
1076 charset);
1079 if (aBodyInit.IsBlob()) {
1080 BodyExtractor<const Blob> body(&aBodyInit.GetAsBlob());
1081 return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
1082 charset);
1085 if (aBodyInit.IsFormData()) {
1086 BodyExtractor<const FormData> body(&aBodyInit.GetAsFormData());
1087 return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
1088 charset);
1091 if (aBodyInit.IsUSVString()) {
1092 BodyExtractor<const nsAString> body(&aBodyInit.GetAsUSVString());
1093 return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
1094 charset);
1097 if (aBodyInit.IsURLSearchParams()) {
1098 BodyExtractor<const URLSearchParams> body(
1099 &aBodyInit.GetAsURLSearchParams());
1100 return body.GetAsStream(aStream, &aContentLength, aContentTypeWithCharset,
1101 charset);
1104 MOZ_ASSERT_UNREACHABLE("Should never reach here");
1105 return NS_ERROR_FAILURE;
1108 template <class Derived>
1109 FetchBody<Derived>::FetchBody(nsIGlobalObject* aOwner)
1110 : mOwner(aOwner),
1111 mWorkerPrivate(nullptr),
1112 mReadableStreamBody(nullptr),
1113 mReadableStreamReader(nullptr),
1114 mBodyUsed(false) {
1115 MOZ_ASSERT(aOwner);
1117 if (!NS_IsMainThread()) {
1118 mWorkerPrivate = GetCurrentThreadWorkerPrivate();
1119 MOZ_ASSERT(mWorkerPrivate);
1120 mMainThreadEventTarget = mWorkerPrivate->MainThreadEventTarget();
1121 } else {
1122 mMainThreadEventTarget = aOwner->EventTargetFor(TaskCategory::Other);
1125 MOZ_ASSERT(mMainThreadEventTarget);
1128 template FetchBody<Request>::FetchBody(nsIGlobalObject* aOwner);
1130 template FetchBody<Response>::FetchBody(nsIGlobalObject* aOwner);
1132 template <class Derived>
1133 FetchBody<Derived>::~FetchBody() {
1134 Unfollow();
1137 template FetchBody<Request>::~FetchBody();
1139 template FetchBody<Response>::~FetchBody();
1141 template <class Derived>
1142 bool FetchBody<Derived>::GetBodyUsed(ErrorResult& aRv) const {
1143 if (mBodyUsed) {
1144 return true;
1147 // If this stream is disturbed, return true.
1148 if (mReadableStreamBody) {
1149 aRv.MightThrowJSException();
1151 AutoJSAPI jsapi;
1152 if (!jsapi.Init(mOwner)) {
1153 aRv.Throw(NS_ERROR_FAILURE);
1154 return true;
1157 JSContext* cx = jsapi.cx();
1158 JS::Rooted<JSObject*> body(cx, mReadableStreamBody);
1159 bool disturbed;
1160 if (!JS::ReadableStreamIsDisturbed(cx, body, &disturbed)) {
1161 aRv.StealExceptionFromJSContext(cx);
1162 return false;
1165 return disturbed;
1168 return false;
1171 template bool FetchBody<Request>::GetBodyUsed(ErrorResult&) const;
1173 template bool FetchBody<Response>::GetBodyUsed(ErrorResult&) const;
1175 template <class Derived>
1176 bool FetchBody<Derived>::CheckBodyUsed() const {
1177 IgnoredErrorResult result;
1178 bool bodyUsed = GetBodyUsed(result);
1179 if (result.Failed()) {
1180 // Ignore the error.
1181 return true;
1183 return bodyUsed;
1186 template <class Derived>
1187 void FetchBody<Derived>::SetBodyUsed(JSContext* aCx, ErrorResult& aRv) {
1188 MOZ_ASSERT(aCx);
1189 MOZ_ASSERT(mOwner->EventTargetFor(TaskCategory::Other)->IsOnCurrentThread());
1191 if (mBodyUsed) {
1192 return;
1195 mBodyUsed = true;
1197 // If we already have a ReadableStreamBody and it has been created by DOM, we
1198 // have to lock it now because it can have been shared with other objects.
1199 if (mReadableStreamBody) {
1200 aRv.MightThrowJSException();
1202 JSAutoRealm ar(aCx, mOwner->GetGlobalJSObject());
1204 JS::Rooted<JSObject*> readableStreamObj(aCx, mReadableStreamBody);
1206 JS::ReadableStreamMode mode;
1207 if (!JS::ReadableStreamGetMode(aCx, readableStreamObj, &mode)) {
1208 aRv.StealExceptionFromJSContext(aCx);
1209 return;
1212 if (mode == JS::ReadableStreamMode::ExternalSource) {
1213 LockStream(aCx, readableStreamObj, aRv);
1214 if (NS_WARN_IF(aRv.Failed())) {
1215 return;
1217 } else {
1218 // If this is not a native ReadableStream, let's activate the
1219 // FetchStreamReader.
1220 MOZ_ASSERT(mFetchStreamReader);
1221 JS::Rooted<JSObject*> reader(aCx);
1222 mFetchStreamReader->StartConsuming(aCx, readableStreamObj, &reader, aRv);
1223 if (NS_WARN_IF(aRv.Failed())) {
1224 return;
1227 mReadableStreamReader = reader;
1232 template void FetchBody<Request>::SetBodyUsed(JSContext* aCx, ErrorResult& aRv);
1234 template void FetchBody<Response>::SetBodyUsed(JSContext* aCx,
1235 ErrorResult& aRv);
1237 template <class Derived>
1238 already_AddRefed<Promise> FetchBody<Derived>::ConsumeBody(
1239 JSContext* aCx, BodyConsumer::ConsumeType aType, ErrorResult& aRv) {
1240 aRv.MightThrowJSException();
1242 RefPtr<AbortSignalImpl> signalImpl = DerivedClass()->GetSignalImpl();
1243 if (signalImpl && signalImpl->Aborted()) {
1244 aRv.Throw(NS_ERROR_DOM_ABORT_ERR);
1245 return nullptr;
1248 bool bodyUsed = GetBodyUsed(aRv);
1249 if (NS_WARN_IF(aRv.Failed())) {
1250 return nullptr;
1252 if (bodyUsed) {
1253 aRv.ThrowTypeError<MSG_FETCH_BODY_CONSUMED_ERROR>();
1254 return nullptr;
1257 nsAutoCString mimeType;
1258 DerivedClass()->GetMimeType(mimeType);
1260 // Null bodies are a special-case in the fetch spec. The Body mix-in can only
1261 // be "disturbed" or "locked" if its associated "body" is non-null.
1262 // Additionally, the Body min-in's "consume body" algorithm explicitly creates
1263 // a fresh empty ReadableStream object in step 2. This means that `bodyUsed`
1264 // will never return true for a null body.
1266 // To this end, we create a fresh (empty) body every time a request is made
1267 // and consume its body here, without marking this FetchBody consumed via
1268 // SetBodyUsed.
1269 nsCOMPtr<nsIInputStream> bodyStream;
1270 DerivedClass()->GetBody(getter_AddRefs(bodyStream));
1271 if (!bodyStream) {
1272 RefPtr<EmptyBody> emptyBody = EmptyBody::Create(
1273 DerivedClass()->GetParentObject(),
1274 DerivedClass()->GetPrincipalInfo().get(), signalImpl, mimeType, aRv);
1275 if (NS_WARN_IF(aRv.Failed())) {
1276 return nullptr;
1279 return emptyBody->ConsumeBody(aCx, aType, aRv);
1282 SetBodyUsed(aCx, aRv);
1283 if (NS_WARN_IF(aRv.Failed())) {
1284 return nullptr;
1287 nsCOMPtr<nsIGlobalObject> global = DerivedClass()->GetParentObject();
1289 MutableBlobStorage::MutableBlobStorageType blobStorageType =
1290 MutableBlobStorage::eOnlyInMemory;
1291 const mozilla::UniquePtr<mozilla::ipc::PrincipalInfo>& principalInfo =
1292 DerivedClass()->GetPrincipalInfo();
1293 // We support temporary file for blobs only if the principal is known and
1294 // it's system or content not in private Browsing.
1295 if (principalInfo &&
1296 (principalInfo->type() ==
1297 mozilla::ipc::PrincipalInfo::TSystemPrincipalInfo ||
1298 (principalInfo->type() ==
1299 mozilla::ipc::PrincipalInfo::TContentPrincipalInfo &&
1300 principalInfo->get_ContentPrincipalInfo().attrs().mPrivateBrowsingId ==
1301 0))) {
1302 blobStorageType = MutableBlobStorage::eCouldBeInTemporaryFile;
1305 RefPtr<Promise> promise = BodyConsumer::Create(
1306 global, mMainThreadEventTarget, bodyStream, signalImpl, aType,
1307 BodyBlobURISpec(), BodyLocalPath(), mimeType, blobStorageType, aRv);
1308 if (NS_WARN_IF(aRv.Failed())) {
1309 return nullptr;
1312 return promise.forget();
1315 template already_AddRefed<Promise> FetchBody<Request>::ConsumeBody(
1316 JSContext* aCx, BodyConsumer::ConsumeType aType, ErrorResult& aRv);
1318 template already_AddRefed<Promise> FetchBody<Response>::ConsumeBody(
1319 JSContext* aCx, BodyConsumer::ConsumeType aType, ErrorResult& aRv);
1321 template already_AddRefed<Promise> FetchBody<EmptyBody>::ConsumeBody(
1322 JSContext* aCx, BodyConsumer::ConsumeType aType, ErrorResult& aRv);
1324 template <class Derived>
1325 void FetchBody<Derived>::GetMimeType(nsACString& aMimeType) {
1326 // Extract mime type.
1327 ErrorResult result;
1328 nsCString contentTypeValues;
1329 MOZ_ASSERT(DerivedClass()->GetInternalHeaders());
1330 DerivedClass()->GetInternalHeaders()->Get("Content-Type"_ns,
1331 contentTypeValues, result);
1332 MOZ_ALWAYS_TRUE(!result.Failed());
1334 // HTTP ABNF states Content-Type may have only one value.
1335 // This is from the "parse a header value" of the fetch spec.
1336 if (!contentTypeValues.IsVoid() && contentTypeValues.Find(",") == -1) {
1337 // Convert from a bytestring to a UTF8 CString.
1338 CopyLatin1toUTF8(contentTypeValues, aMimeType);
1339 ToLowerCase(aMimeType);
1343 template void FetchBody<Request>::GetMimeType(nsACString& aMimeType);
1344 template void FetchBody<Response>::GetMimeType(nsACString& aMimeType);
1346 template <class Derived>
1347 const nsACString& FetchBody<Derived>::BodyBlobURISpec() const {
1348 return DerivedClass()->BodyBlobURISpec();
1351 template const nsACString& FetchBody<Request>::BodyBlobURISpec() const;
1353 template const nsACString& FetchBody<Response>::BodyBlobURISpec() const;
1355 template const nsACString& FetchBody<EmptyBody>::BodyBlobURISpec() const;
1357 template <class Derived>
1358 const nsAString& FetchBody<Derived>::BodyLocalPath() const {
1359 return DerivedClass()->BodyLocalPath();
1362 template const nsAString& FetchBody<Request>::BodyLocalPath() const;
1364 template const nsAString& FetchBody<Response>::BodyLocalPath() const;
1366 template const nsAString& FetchBody<EmptyBody>::BodyLocalPath() const;
1368 template <class Derived>
1369 void FetchBody<Derived>::SetReadableStreamBody(JSContext* aCx,
1370 JSObject* aBody) {
1371 MOZ_ASSERT(!mReadableStreamBody);
1372 MOZ_ASSERT(aBody);
1373 mReadableStreamBody = aBody;
1375 RefPtr<AbortSignalImpl> signalImpl = DerivedClass()->GetSignalImpl();
1376 if (!signalImpl) {
1377 return;
1380 bool aborted = signalImpl->Aborted();
1381 if (aborted) {
1382 JS::Rooted<JSObject*> body(aCx, mReadableStreamBody);
1383 IgnoredErrorResult result;
1384 AbortStream(aCx, body, result);
1385 if (NS_WARN_IF(result.Failed())) {
1386 return;
1388 } else if (!IsFollowing()) {
1389 Follow(signalImpl);
1393 template void FetchBody<Request>::SetReadableStreamBody(JSContext* aCx,
1394 JSObject* aBody);
1396 template void FetchBody<Response>::SetReadableStreamBody(JSContext* aCx,
1397 JSObject* aBody);
1399 template <class Derived>
1400 void FetchBody<Derived>::GetBody(JSContext* aCx,
1401 JS::MutableHandle<JSObject*> aBodyOut,
1402 ErrorResult& aRv) {
1403 if (mReadableStreamBody) {
1404 aBodyOut.set(mReadableStreamBody);
1405 return;
1408 nsCOMPtr<nsIInputStream> inputStream;
1409 DerivedClass()->GetBody(getter_AddRefs(inputStream));
1411 if (!inputStream) {
1412 aBodyOut.set(nullptr);
1413 return;
1416 BodyStream::Create(aCx, this, DerivedClass()->GetParentObject(), inputStream,
1417 aRv);
1418 if (NS_WARN_IF(aRv.Failed())) {
1419 return;
1422 MOZ_ASSERT(mReadableStreamBody);
1424 JS::Rooted<JSObject*> body(aCx, mReadableStreamBody);
1426 // If the body has been already consumed, we lock the stream.
1427 bool bodyUsed = GetBodyUsed(aRv);
1428 if (NS_WARN_IF(aRv.Failed())) {
1429 return;
1431 if (bodyUsed) {
1432 LockStream(aCx, body, aRv);
1433 if (NS_WARN_IF(aRv.Failed())) {
1434 return;
1438 RefPtr<AbortSignalImpl> signalImpl = DerivedClass()->GetSignalImpl();
1439 if (signalImpl) {
1440 if (signalImpl->Aborted()) {
1441 AbortStream(aCx, body, aRv);
1442 if (NS_WARN_IF(aRv.Failed())) {
1443 return;
1445 } else if (!IsFollowing()) {
1446 Follow(signalImpl);
1450 aBodyOut.set(mReadableStreamBody);
1453 template void FetchBody<Request>::GetBody(JSContext* aCx,
1454 JS::MutableHandle<JSObject*> aMessage,
1455 ErrorResult& aRv);
1457 template void FetchBody<Response>::GetBody(
1458 JSContext* aCx, JS::MutableHandle<JSObject*> aMessage, ErrorResult& aRv);
1460 template <class Derived>
1461 void FetchBody<Derived>::LockStream(JSContext* aCx, JS::HandleObject aStream,
1462 ErrorResult& aRv) {
1463 aRv.MightThrowJSException();
1465 #if DEBUG
1466 JS::ReadableStreamMode streamMode;
1467 if (!JS::ReadableStreamGetMode(aCx, aStream, &streamMode)) {
1468 aRv.StealExceptionFromJSContext(aCx);
1469 return;
1471 MOZ_ASSERT(streamMode == JS::ReadableStreamMode::ExternalSource);
1472 #endif // DEBUG
1474 // This is native stream, creating a reader will not execute any JS code.
1475 JS::Rooted<JSObject*> reader(
1476 aCx, JS::ReadableStreamGetReader(aCx, aStream,
1477 JS::ReadableStreamReaderMode::Default));
1478 if (!reader) {
1479 aRv.StealExceptionFromJSContext(aCx);
1480 return;
1483 mReadableStreamReader = reader;
1486 template void FetchBody<Request>::LockStream(JSContext* aCx,
1487 JS::HandleObject aStream,
1488 ErrorResult& aRv);
1490 template void FetchBody<Response>::LockStream(JSContext* aCx,
1491 JS::HandleObject aStream,
1492 ErrorResult& aRv);
1494 template <class Derived>
1495 void FetchBody<Derived>::MaybeTeeReadableStreamBody(
1496 JSContext* aCx, JS::MutableHandle<JSObject*> aBodyOut,
1497 FetchStreamReader** aStreamReader, nsIInputStream** aInputStream,
1498 ErrorResult& aRv) {
1499 MOZ_DIAGNOSTIC_ASSERT(aStreamReader);
1500 MOZ_DIAGNOSTIC_ASSERT(aInputStream);
1501 MOZ_DIAGNOSTIC_ASSERT(!CheckBodyUsed());
1503 aBodyOut.set(nullptr);
1504 *aStreamReader = nullptr;
1505 *aInputStream = nullptr;
1507 if (!mReadableStreamBody) {
1508 return;
1511 aRv.MightThrowJSException();
1513 JSAutoRealm ar(aCx, mOwner->GetGlobalJSObject());
1515 JS::Rooted<JSObject*> stream(aCx, mReadableStreamBody);
1517 // If this is a ReadableStream with an external source, this has been
1518 // generated by a Fetch. In this case, Fetch will be able to recreate it
1519 // again when GetBody() is called.
1520 JS::ReadableStreamMode streamMode;
1521 if (!JS::ReadableStreamGetMode(aCx, stream, &streamMode)) {
1522 aRv.StealExceptionFromJSContext(aCx);
1523 return;
1525 if (streamMode == JS::ReadableStreamMode::ExternalSource) {
1526 aBodyOut.set(nullptr);
1527 return;
1530 JS::Rooted<JSObject*> branch1(aCx);
1531 JS::Rooted<JSObject*> branch2(aCx);
1533 if (!JS::ReadableStreamTee(aCx, stream, &branch1, &branch2)) {
1534 aRv.StealExceptionFromJSContext(aCx);
1535 return;
1538 mReadableStreamBody = branch1;
1539 aBodyOut.set(branch2);
1541 aRv = FetchStreamReader::Create(aCx, mOwner, aStreamReader, aInputStream);
1542 if (NS_WARN_IF(aRv.Failed())) {
1543 return;
1547 template void FetchBody<Request>::MaybeTeeReadableStreamBody(
1548 JSContext* aCx, JS::MutableHandle<JSObject*> aMessage,
1549 FetchStreamReader** aStreamReader, nsIInputStream** aInputStream,
1550 ErrorResult& aRv);
1552 template void FetchBody<Response>::MaybeTeeReadableStreamBody(
1553 JSContext* aCx, JS::MutableHandle<JSObject*> aMessage,
1554 FetchStreamReader** aStreamReader, nsIInputStream** aInputStream,
1555 ErrorResult& aRv);
1557 template <class Derived>
1558 void FetchBody<Derived>::RunAbortAlgorithm() {
1559 if (!mReadableStreamBody) {
1560 return;
1563 AutoJSAPI jsapi;
1564 if (!jsapi.Init(mOwner)) {
1565 return;
1568 JSContext* cx = jsapi.cx();
1570 JS::Rooted<JSObject*> body(cx, mReadableStreamBody);
1571 IgnoredErrorResult result;
1572 AbortStream(cx, body, result);
1575 template void FetchBody<Request>::RunAbortAlgorithm();
1577 template void FetchBody<Response>::RunAbortAlgorithm();
1579 } // namespace mozilla::dom