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/. */
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
{
54 void AbortStream(JSContext
* aCx
, JS::Handle
<JSObject
*> aStream
,
56 aRv
.MightThrowJSException();
59 if (!JS::ReadableStreamIsReadable(aCx
, aStream
, &isReadable
)) {
60 aRv
.StealExceptionFromJSContext(aCx
);
67 RefPtr
<DOMException
> e
= DOMException::Create(NS_ERROR_DOM_ABORT_ERR
);
69 JS::Rooted
<JS::Value
> value(aCx
);
70 if (!GetOrCreateDOMReflector(aCx
, e
, &value
)) {
74 if (!JS::ReadableStreamError(aCx
, aStream
, value
)) {
75 aRv
.StealExceptionFromJSContext(aCx
);
81 class AbortSignalMainThread final
: public AbortSignalImpl
{
83 NS_DECL_CYCLE_COLLECTING_ISUPPORTS
84 NS_DECL_CYCLE_COLLECTION_CLASS(AbortSignalMainThread
)
86 explicit AbortSignalMainThread(bool aAborted
) : AbortSignalImpl(aAborted
) {}
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
)
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
;
123 explicit AbortSignalProxyRunnable(AbortSignalProxy
* aProxy
)
124 : Runnable("dom::WorkerSignalFollower::AbortSignalProxyRunnable"),
127 NS_IMETHOD
Run() override
;
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.
142 void RunAbortAlgorithm() override
;
145 MOZ_ASSERT(!NS_IsMainThread());
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
)
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
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
; }
229 MOZ_ASSERT(!NS_IsMainThread());
230 mWorkerSignalFollower
->Shutdown();
231 mWorkerSignalFollower
= nullptr;
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();
251 void WorkerSignalFollower::RunAbortAlgorithm() {
252 MOZ_ASSERT(!NS_IsMainThread());
253 RefPtr
<AbortSignalProxyRunnable
> runnable
=
254 new AbortSignalProxyRunnable(mProxy
);
255 mProxy
->MainThreadEventTarget()->Dispatch(runnable
.forget(),
259 class WorkerFetchResolver final
: public FetchDriverObserver
{
261 RefPtr
<PromiseWorkerProxy
> mPromiseProxy
;
262 RefPtr
<AbortSignalProxy
> mSignalProxy
;
264 // Touched only on the worker thread.
265 RefPtr
<FetchObserver
> mFetchObserver
;
266 RefPtr
<WeakWorkerRef
> mWorkerRef
;
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
);
282 RefPtr
<AbortSignalProxy
> signalProxy
;
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
)) {
297 r
->mWorkerRef
= std::move(workerRef
);
302 AbortSignalImpl
* GetAbortSignalForMainThread() {
303 MOZ_ASSERT(NS_IsMainThread());
309 return mSignalProxy
->GetOrCreateSignalImplForMainThread();
312 AbortSignalImpl
* GetAbortSignalForTargetThread() {
313 mPromiseProxy
->GetWorkerPrivate()->AssertIsOnWorkerThread();
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();
355 mPromiseProxy
->CleanUp();
357 mFetchObserver
= nullptr;
360 mSignalProxy
->Shutdown();
361 mSignalProxy
= nullptr;
364 mWorkerRef
= nullptr;
367 bool IsShutdown(WorkerPrivate
* aWorkerPrivate
) const {
368 MOZ_ASSERT(aWorkerPrivate
);
369 aWorkerPrivate
->AssertIsOnWorkerThread();
374 WorkerFetchResolver(PromiseWorkerProxy
* aProxy
,
375 AbortSignalProxy
* aSignalProxy
, FetchObserver
* aObserver
)
376 : mPromiseProxy(aProxy
),
377 mSignalProxy(aSignalProxy
),
378 mFetchObserver(aObserver
),
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
;
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
;
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
;
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
);
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");
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);
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
,
511 RefPtr
<Promise
> p
= Promise::Create(aGlobal
, aRv
);
512 if (NS_WARN_IF(aRv
.Failed())) {
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
);
525 if (!jsapi
.Init(aGlobal
)) {
526 aRv
.Throw(NS_ERROR_NOT_AVAILABLE
);
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
);
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
);
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;
563 doc
= window
->GetExtantDoc();
565 aRv
.Throw(NS_ERROR_FAILURE
);
568 principal
= doc
->NodePrincipal();
569 loadGroup
= doc
->GetDocumentLoadGroup();
570 cookieJarSettings
= doc
->CookieJarSettings();
572 isTrackingFetch
= doc
->IsScriptTracking(cx
);
574 principal
= aGlobal
->PrincipalOrNull();
575 if (NS_WARN_IF(!principal
)) {
576 aRv
.Throw(NS_ERROR_FAILURE
);
580 cookieJarSettings
= mozilla::net::CookieJarSettings::Create(principal
);
584 nsresult rv
= NS_NewLoadGroup(getter_AddRefs(loadGroup
), principal
);
585 if (NS_WARN_IF(NS_FAILED(rv
))) {
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
598 fetch
->SetDocument(doc
);
599 resolver
->SetLoadGroup(loadGroup
);
600 aRv
= fetch
->Fetch(signalImpl
, resolver
);
601 if (NS_WARN_IF(aRv
.Failed())) {
605 WorkerPrivate
* worker
= GetCurrentThreadWorkerPrivate();
608 if (worker
->IsServiceWorker()) {
609 r
->SetSkipServiceWorker();
612 RefPtr
<WorkerFetchResolver
> resolver
=
613 WorkerFetchResolver::Create(worker
, p
, signalImpl
, observer
);
615 NS_WARNING("Could not keep the worker alive.");
616 aRv
.Throw(NS_ERROR_DOM_ABORT_ERR
);
620 Maybe
<ClientInfo
> clientInfo(worker
->GlobalScope()->GetClientInfo());
621 if (clientInfo
.isNothing()) {
622 aRv
.Throw(NS_ERROR_DOM_INVALID_STATE_ERR
);
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());
640 class ResolveFetchPromise
: public Runnable
{
642 ResolveFetchPromise(Promise
* aPromise
, Response
* aResponse
)
643 : Runnable("ResolveFetchPromise"),
645 mResponse(aResponse
) {}
648 mPromise
->MaybeResolve(mResponse
);
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;
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
));
684 mPromise
->MaybeResolve(mResponse
);
687 if (mFetchObserver
) {
688 mFetchObserver
->SetState(FetchState::Errored
);
692 mPromise
->MaybeReject(aResponse
->GetErrorCode());
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
) {
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
;
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
) {
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
);
757 fetchObserver
->SetState(FetchState::Errored
);
760 promise
->MaybeRejectWithTypeError
<MSG_FETCH_FAILED
>();
766 class WorkerDataAvailableRunnable final
: public MainThreadWorkerRunnable
{
767 RefPtr
<WorkerFetchResolver
> mResolver
;
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
);
789 class WorkerFetchResponseEndBase
{
791 RefPtr
<WorkerFetchResolver
> mResolver
;
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
;
809 WorkerFetchResponseEndRunnable(WorkerPrivate
* aWorkerPrivate
,
810 WorkerFetchResolver
* aResolver
,
811 FetchDriverObserver::EndReason aReason
)
812 : MainThreadWorkerRunnable(aWorkerPrivate
),
813 WorkerFetchResponseEndBase(aResolver
),
816 bool WorkerRun(JSContext
* aCx
, WorkerPrivate
* aWorkerPrivate
) override
{
817 if (mResolver
->IsShutdown(aWorkerPrivate
)) {
821 if (mReason
== FetchDriverObserver::eAborted
) {
822 mResolver
->WorkerPromise(aWorkerPrivate
)
823 ->MaybeReject(NS_ERROR_DOM_ABORT_ERR
);
826 WorkerRunInternal(aWorkerPrivate
);
830 nsresult
Cancel() override
{
831 // Execute Run anyway to make sure we cleanup our promise proxy to avoid
832 // leaking the worker thread
834 return WorkerRunnable::Cancel();
838 class WorkerFetchResponseEndControlRunnable final
839 : public MainThreadWorkerControlRunnable
,
840 public WorkerFetchResponseEndBase
{
842 WorkerFetchResponseEndControlRunnable(WorkerPrivate
* aWorkerPrivate
,
843 WorkerFetchResolver
* aResolver
)
844 : MainThreadWorkerControlRunnable(aWorkerPrivate
),
845 WorkerFetchResponseEndBase(aResolver
) {}
847 bool WorkerRun(JSContext
* aCx
, WorkerPrivate
* aWorkerPrivate
) override
{
848 WorkerRunInternal(aWorkerPrivate
);
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()) {
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()) {
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()) {
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
);
925 WorkerPrivate
* worker
= mPromiseProxy
->GetWorkerPrivate();
927 mReporter
->FlushReportsToConsole(0);
931 if (worker
->IsServiceWorker()) {
932 // Flush to service worker
933 mReporter
->FlushReportsToConsoleForServiceWorkerScope(
934 worker
->ServiceWorkerScope());
938 if (worker
->IsSharedWorker()) {
939 // Flush to shared worker
940 worker
->GetRemoteWorkerController()->FlushReportsOnMainThread(mReporter
);
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
) {
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
,
962 if (aBodyInit
.IsArrayBufferView()) {
963 BodyExtractor
<const ArrayBufferView
> body(
964 &aBodyInit
.GetAsArrayBufferView());
965 return body
.GetAsStream(aStream
, &aContentLength
, aContentTypeWithCharset
,
969 if (aBodyInit
.IsBlob()) {
970 Blob
& blob
= aBodyInit
.GetAsBlob();
971 BodyExtractor
<const Blob
> body(&blob
);
972 return body
.GetAsStream(aStream
, &aContentLength
, aContentTypeWithCharset
,
976 if (aBodyInit
.IsFormData()) {
977 FormData
& formData
= aBodyInit
.GetAsFormData();
978 BodyExtractor
<const FormData
> body(&formData
);
979 return body
.GetAsStream(aStream
, &aContentLength
, aContentTypeWithCharset
,
983 if (aBodyInit
.IsUSVString()) {
984 BodyExtractor
<const nsAString
> body(&aBodyInit
.GetAsUSVString());
985 return body
.GetAsStream(aStream
, &aContentLength
, aContentTypeWithCharset
,
989 if (aBodyInit
.IsURLSearchParams()) {
990 URLSearchParams
& usp
= aBodyInit
.GetAsURLSearchParams();
991 BodyExtractor
<const URLSearchParams
> body(&usp
);
992 return body
.GetAsStream(aStream
, &aContentLength
, aContentTypeWithCharset
,
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
,
1016 if (aBodyInit
.IsArrayBufferView()) {
1017 BodyExtractor
<const ArrayBufferView
> body(
1018 &aBodyInit
.GetAsArrayBufferView());
1019 return body
.GetAsStream(aStream
, &aContentLength
, aContentTypeWithCharset
,
1023 if (aBodyInit
.IsBlob()) {
1024 BodyExtractor
<const Blob
> body(&aBodyInit
.GetAsBlob());
1025 return body
.GetAsStream(aStream
, &aContentLength
, aContentTypeWithCharset
,
1029 if (aBodyInit
.IsFormData()) {
1030 BodyExtractor
<const FormData
> body(&aBodyInit
.GetAsFormData());
1031 return body
.GetAsStream(aStream
, &aContentLength
, aContentTypeWithCharset
,
1035 if (aBodyInit
.IsUSVString()) {
1036 BodyExtractor
<const nsAString
> body(&aBodyInit
.GetAsUSVString());
1037 return body
.GetAsStream(aStream
, &aContentLength
, aContentTypeWithCharset
,
1041 if (aBodyInit
.IsURLSearchParams()) {
1042 BodyExtractor
<const URLSearchParams
> body(
1043 &aBodyInit
.GetAsURLSearchParams());
1044 return body
.GetAsStream(aStream
, &aContentLength
, aContentTypeWithCharset
,
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
,
1072 if (aBodyInit
.IsArrayBufferView()) {
1073 BodyExtractor
<const ArrayBufferView
> body(
1074 &aBodyInit
.GetAsArrayBufferView());
1075 return body
.GetAsStream(aStream
, &aContentLength
, aContentTypeWithCharset
,
1079 if (aBodyInit
.IsBlob()) {
1080 BodyExtractor
<const Blob
> body(&aBodyInit
.GetAsBlob());
1081 return body
.GetAsStream(aStream
, &aContentLength
, aContentTypeWithCharset
,
1085 if (aBodyInit
.IsFormData()) {
1086 BodyExtractor
<const FormData
> body(&aBodyInit
.GetAsFormData());
1087 return body
.GetAsStream(aStream
, &aContentLength
, aContentTypeWithCharset
,
1091 if (aBodyInit
.IsUSVString()) {
1092 BodyExtractor
<const nsAString
> body(&aBodyInit
.GetAsUSVString());
1093 return body
.GetAsStream(aStream
, &aContentLength
, aContentTypeWithCharset
,
1097 if (aBodyInit
.IsURLSearchParams()) {
1098 BodyExtractor
<const URLSearchParams
> body(
1099 &aBodyInit
.GetAsURLSearchParams());
1100 return body
.GetAsStream(aStream
, &aContentLength
, aContentTypeWithCharset
,
1104 MOZ_ASSERT_UNREACHABLE("Should never reach here");
1105 return NS_ERROR_FAILURE
;
1108 template <class Derived
>
1109 FetchBody
<Derived
>::FetchBody(nsIGlobalObject
* aOwner
)
1111 mWorkerPrivate(nullptr),
1112 mReadableStreamBody(nullptr),
1113 mReadableStreamReader(nullptr),
1117 if (!NS_IsMainThread()) {
1118 mWorkerPrivate
= GetCurrentThreadWorkerPrivate();
1119 MOZ_ASSERT(mWorkerPrivate
);
1120 mMainThreadEventTarget
= mWorkerPrivate
->MainThreadEventTarget();
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() {
1137 template FetchBody
<Request
>::~FetchBody();
1139 template FetchBody
<Response
>::~FetchBody();
1141 template <class Derived
>
1142 bool FetchBody
<Derived
>::GetBodyUsed(ErrorResult
& aRv
) const {
1147 // If this stream is disturbed, return true.
1148 if (mReadableStreamBody
) {
1149 aRv
.MightThrowJSException();
1152 if (!jsapi
.Init(mOwner
)) {
1153 aRv
.Throw(NS_ERROR_FAILURE
);
1157 JSContext
* cx
= jsapi
.cx();
1158 JS::Rooted
<JSObject
*> body(cx
, mReadableStreamBody
);
1160 if (!JS::ReadableStreamIsDisturbed(cx
, body
, &disturbed
)) {
1161 aRv
.StealExceptionFromJSContext(cx
);
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.
1186 template <class Derived
>
1187 void FetchBody
<Derived
>::SetBodyUsed(JSContext
* aCx
, ErrorResult
& aRv
) {
1189 MOZ_ASSERT(mOwner
->EventTargetFor(TaskCategory::Other
)->IsOnCurrentThread());
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
);
1212 if (mode
== JS::ReadableStreamMode::ExternalSource
) {
1213 LockStream(aCx
, readableStreamObj
, aRv
);
1214 if (NS_WARN_IF(aRv
.Failed())) {
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())) {
1227 mReadableStreamReader
= reader
;
1232 template void FetchBody
<Request
>::SetBodyUsed(JSContext
* aCx
, ErrorResult
& aRv
);
1234 template void FetchBody
<Response
>::SetBodyUsed(JSContext
* aCx
,
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
);
1248 bool bodyUsed
= GetBodyUsed(aRv
);
1249 if (NS_WARN_IF(aRv
.Failed())) {
1253 aRv
.ThrowTypeError
<MSG_FETCH_BODY_CONSUMED_ERROR
>();
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
1269 nsCOMPtr
<nsIInputStream
> bodyStream
;
1270 DerivedClass()->GetBody(getter_AddRefs(bodyStream
));
1272 RefPtr
<EmptyBody
> emptyBody
= EmptyBody::Create(
1273 DerivedClass()->GetParentObject(),
1274 DerivedClass()->GetPrincipalInfo().get(), signalImpl
, mimeType
, aRv
);
1275 if (NS_WARN_IF(aRv
.Failed())) {
1279 return emptyBody
->ConsumeBody(aCx
, aType
, aRv
);
1282 SetBodyUsed(aCx
, aRv
);
1283 if (NS_WARN_IF(aRv
.Failed())) {
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
==
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())) {
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.
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
,
1371 MOZ_ASSERT(!mReadableStreamBody
);
1373 mReadableStreamBody
= aBody
;
1375 RefPtr
<AbortSignalImpl
> signalImpl
= DerivedClass()->GetSignalImpl();
1380 bool aborted
= signalImpl
->Aborted();
1382 JS::Rooted
<JSObject
*> body(aCx
, mReadableStreamBody
);
1383 IgnoredErrorResult result
;
1384 AbortStream(aCx
, body
, result
);
1385 if (NS_WARN_IF(result
.Failed())) {
1388 } else if (!IsFollowing()) {
1393 template void FetchBody
<Request
>::SetReadableStreamBody(JSContext
* aCx
,
1396 template void FetchBody
<Response
>::SetReadableStreamBody(JSContext
* aCx
,
1399 template <class Derived
>
1400 void FetchBody
<Derived
>::GetBody(JSContext
* aCx
,
1401 JS::MutableHandle
<JSObject
*> aBodyOut
,
1403 if (mReadableStreamBody
) {
1404 aBodyOut
.set(mReadableStreamBody
);
1408 nsCOMPtr
<nsIInputStream
> inputStream
;
1409 DerivedClass()->GetBody(getter_AddRefs(inputStream
));
1412 aBodyOut
.set(nullptr);
1416 BodyStream::Create(aCx
, this, DerivedClass()->GetParentObject(), inputStream
,
1418 if (NS_WARN_IF(aRv
.Failed())) {
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())) {
1432 LockStream(aCx
, body
, aRv
);
1433 if (NS_WARN_IF(aRv
.Failed())) {
1438 RefPtr
<AbortSignalImpl
> signalImpl
= DerivedClass()->GetSignalImpl();
1440 if (signalImpl
->Aborted()) {
1441 AbortStream(aCx
, body
, aRv
);
1442 if (NS_WARN_IF(aRv
.Failed())) {
1445 } else if (!IsFollowing()) {
1450 aBodyOut
.set(mReadableStreamBody
);
1453 template void FetchBody
<Request
>::GetBody(JSContext
* aCx
,
1454 JS::MutableHandle
<JSObject
*> aMessage
,
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
,
1463 aRv
.MightThrowJSException();
1466 JS::ReadableStreamMode streamMode
;
1467 if (!JS::ReadableStreamGetMode(aCx
, aStream
, &streamMode
)) {
1468 aRv
.StealExceptionFromJSContext(aCx
);
1471 MOZ_ASSERT(streamMode
== JS::ReadableStreamMode::ExternalSource
);
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
));
1479 aRv
.StealExceptionFromJSContext(aCx
);
1483 mReadableStreamReader
= reader
;
1486 template void FetchBody
<Request
>::LockStream(JSContext
* aCx
,
1487 JS::HandleObject aStream
,
1490 template void FetchBody
<Response
>::LockStream(JSContext
* aCx
,
1491 JS::HandleObject aStream
,
1494 template <class Derived
>
1495 void FetchBody
<Derived
>::MaybeTeeReadableStreamBody(
1496 JSContext
* aCx
, JS::MutableHandle
<JSObject
*> aBodyOut
,
1497 FetchStreamReader
** aStreamReader
, nsIInputStream
** aInputStream
,
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
) {
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
);
1525 if (streamMode
== JS::ReadableStreamMode::ExternalSource
) {
1526 aBodyOut
.set(nullptr);
1530 JS::Rooted
<JSObject
*> branch1(aCx
);
1531 JS::Rooted
<JSObject
*> branch2(aCx
);
1533 if (!JS::ReadableStreamTee(aCx
, stream
, &branch1
, &branch2
)) {
1534 aRv
.StealExceptionFromJSContext(aCx
);
1538 mReadableStreamBody
= branch1
;
1539 aBodyOut
.set(branch2
);
1541 aRv
= FetchStreamReader::Create(aCx
, mOwner
, aStreamReader
, aInputStream
);
1542 if (NS_WARN_IF(aRv
.Failed())) {
1547 template void FetchBody
<Request
>::MaybeTeeReadableStreamBody(
1548 JSContext
* aCx
, JS::MutableHandle
<JSObject
*> aMessage
,
1549 FetchStreamReader
** aStreamReader
, nsIInputStream
** aInputStream
,
1552 template void FetchBody
<Response
>::MaybeTeeReadableStreamBody(
1553 JSContext
* aCx
, JS::MutableHandle
<JSObject
*> aMessage
,
1554 FetchStreamReader
** aStreamReader
, nsIInputStream
** aInputStream
,
1557 template <class Derived
>
1558 void FetchBody
<Derived
>::RunAbortAlgorithm() {
1559 if (!mReadableStreamBody
) {
1564 if (!jsapi
.Init(mOwner
)) {
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