1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "FetchParent.h"
7 #include "nsContentUtils.h"
8 #include "nsIContentSecurityPolicy.h"
9 #include "nsICookieJarSettings.h"
10 #include "nsILoadGroup.h"
11 #include "nsILoadInfo.h"
12 #include "nsIIOService.h"
13 #include "nsIObserverService.h"
14 #include "nsIPrincipal.h"
15 #include "nsIScriptSecurityManager.h"
16 #include "nsNetUtil.h"
17 #include "nsThreadUtils.h"
18 #include "nsXULAppAPI.h"
19 #include "mozilla/BasePrincipal.h"
20 #include "mozilla/ClearOnShutdown.h"
21 #include "mozilla/SchedulerGroup.h"
22 #include "mozilla/ScopeExit.h"
23 #include "mozilla/UniquePtr.h"
24 #include "mozilla/dom/ClientInfo.h"
25 #include "mozilla/dom/FetchService.h"
26 #include "mozilla/dom/InternalRequest.h"
27 #include "mozilla/dom/InternalResponse.h"
28 #include "mozilla/dom/PerformanceStorage.h"
29 #include "mozilla/dom/PerformanceTiming.h"
30 #include "mozilla/dom/ServiceWorkerDescriptor.h"
31 #include "mozilla/ipc/BackgroundUtils.h"
32 #include "mozilla/net/CookieJarSettings.h"
34 namespace mozilla::dom
{
36 mozilla::LazyLogModule
gFetchLog("Fetch");
38 // FetchServicePromises
40 FetchServicePromises::FetchServicePromises()
42 MakeRefPtr
<FetchServiceResponseAvailablePromise::Private
>(__func__
)),
44 MakeRefPtr
<FetchServiceResponseTimingPromise::Private
>(__func__
)),
46 MakeRefPtr
<FetchServiceResponseEndPromise::Private
>(__func__
)) {
47 mAvailablePromise
->UseSynchronousTaskDispatch(__func__
);
48 mTimingPromise
->UseSynchronousTaskDispatch(__func__
);
49 mEndPromise
->UseSynchronousTaskDispatch(__func__
);
52 RefPtr
<FetchServiceResponseAvailablePromise
>
53 FetchServicePromises::GetResponseAvailablePromise() {
54 return mAvailablePromise
;
57 RefPtr
<FetchServiceResponseTimingPromise
>
58 FetchServicePromises::GetResponseTimingPromise() {
59 return mTimingPromise
;
62 RefPtr
<FetchServiceResponseEndPromise
>
63 FetchServicePromises::GetResponseEndPromise() {
67 void FetchServicePromises::ResolveResponseAvailablePromise(
68 FetchServiceResponse
&& aResponse
, const char* aMethodName
) {
69 if (mAvailablePromise
) {
70 mAvailablePromise
->Resolve(std::move(aResponse
), aMethodName
);
74 void FetchServicePromises::RejectResponseAvailablePromise(
75 const CopyableErrorResult
&& aError
, const char* aMethodName
) {
76 if (mAvailablePromise
) {
77 mAvailablePromise
->Reject(aError
, aMethodName
);
81 void FetchServicePromises::ResolveResponseTimingPromise(
82 ResponseTiming
&& aTiming
, const char* aMethodName
) {
84 mTimingPromise
->Resolve(std::move(aTiming
), aMethodName
);
88 void FetchServicePromises::RejectResponseTimingPromise(
89 const CopyableErrorResult
&& aError
, const char* aMethodName
) {
91 mTimingPromise
->Reject(aError
, aMethodName
);
95 void FetchServicePromises::ResolveResponseEndPromise(ResponseEndArgs
&& aArgs
,
96 const char* aMethodName
) {
98 mEndPromise
->Resolve(std::move(aArgs
), aMethodName
);
102 void FetchServicePromises::RejectResponseEndPromise(
103 const CopyableErrorResult
&& aError
, const char* aMethodName
) {
105 mEndPromise
->Reject(aError
, aMethodName
);
111 nsresult
FetchService::FetchInstance::Initialize(FetchArgs
&& aArgs
) {
112 MOZ_ASSERT(XRE_IsParentProcess());
113 MOZ_ASSERT(NS_IsMainThread());
114 MOZ_ASSERT(!aArgs
.is
<UnknownArgs
>() && mArgs
.is
<UnknownArgs
>());
116 mArgs
= std::move(aArgs
);
118 // Get needed information for FetchDriver from passed-in channel.
119 if (mArgs
.is
<NavigationPreloadArgs
>()) {
120 mRequest
= mArgs
.as
<NavigationPreloadArgs
>().mRequest
.clonePtr();
121 nsIChannel
* channel
= mArgs
.as
<NavigationPreloadArgs
>().mChannel
;
122 FETCH_LOG(("FetchInstance::Initialize [%p] request[%p], channel[%p]", this,
123 mRequest
.unsafeGetRawPtr(), channel
));
126 nsCOMPtr
<nsILoadInfo
> loadInfo
= channel
->LoadInfo();
127 MOZ_ASSERT(loadInfo
);
129 nsCOMPtr
<nsIURI
> channelURI
;
130 rv
= channel
->GetURI(getter_AddRefs(channelURI
));
131 if (NS_WARN_IF(NS_FAILED(rv
))) {
135 nsIScriptSecurityManager
* securityManager
=
136 nsContentUtils::GetSecurityManager();
137 if (securityManager
) {
138 securityManager
->GetChannelResultPrincipal(channel
,
139 getter_AddRefs(mPrincipal
));
143 return NS_ERROR_UNEXPECTED
;
146 // Get loadGroup from channel
147 rv
= channel
->GetLoadGroup(getter_AddRefs(mLoadGroup
));
148 if (NS_WARN_IF(NS_FAILED(rv
))) {
152 rv
= NS_NewLoadGroup(getter_AddRefs(mLoadGroup
), mPrincipal
);
153 if (NS_WARN_IF(NS_FAILED(rv
))) {
158 // Get CookieJarSettings from channel
159 rv
= loadInfo
->GetCookieJarSettings(getter_AddRefs(mCookieJarSettings
));
160 if (NS_WARN_IF(NS_FAILED(rv
))) {
164 // Get PerformanceStorage from channel
165 mPerformanceStorage
= loadInfo
->GetPerformanceStorage();
167 mIsWorkerFetch
= true;
168 mRequest
= mArgs
.as
<WorkerFetchArgs
>().mRequest
.clonePtr();
170 FETCH_LOG(("FetchInstance::Initialize [%p] request[%p]", this,
171 mRequest
.unsafeGetRawPtr()));
173 auto principalOrErr
=
174 PrincipalInfoToPrincipal(mArgs
.as
<WorkerFetchArgs
>().mPrincipalInfo
);
175 if (principalOrErr
.isErr()) {
176 return principalOrErr
.unwrapErr();
178 mPrincipal
= principalOrErr
.unwrap();
179 nsresult rv
= NS_NewLoadGroup(getter_AddRefs(mLoadGroup
), mPrincipal
);
180 if (NS_WARN_IF(NS_FAILED(rv
))) {
184 if (mArgs
.as
<WorkerFetchArgs
>().mCookieJarSettings
.isSome()) {
185 net::CookieJarSettings::Deserialize(
186 mArgs
.as
<WorkerFetchArgs
>().mCookieJarSettings
.ref(),
187 getter_AddRefs(mCookieJarSettings
));
194 RefPtr
<FetchServicePromises
> FetchService::FetchInstance::Fetch() {
195 MOZ_ASSERT(XRE_IsParentProcess());
196 MOZ_ASSERT(NS_IsMainThread());
198 MOZ_ASSERT(mPrincipal
);
199 MOZ_ASSERT(mLoadGroup
);
201 nsAutoCString principalSpec
;
202 MOZ_ALWAYS_SUCCEEDS(mPrincipal
->GetAsciiSpec(principalSpec
));
203 nsAutoCString requestURL
;
204 mRequest
->GetURL(requestURL
);
205 FETCH_LOG(("FetchInstance::Fetch [%p], mRequest URL: %s mPrincipal: %s", this,
206 requestURL
.BeginReading(), principalSpec
.BeginReading()));
210 // Create a FetchDriver instance
211 mFetchDriver
= MakeRefPtr
<FetchDriver
>(
212 mRequest
.clonePtr(), // Fetch Request
213 mPrincipal
, // Principal
214 mLoadGroup
, // LoadGroup
215 GetMainThreadSerialEventTarget(), // MainThreadEventTarget
216 mCookieJarSettings
, // CookieJarSettings
217 mPerformanceStorage
, // PerformanceStorage
218 false // IsTrackingFetch
221 if (mIsWorkerFetch
) {
222 auto& args
= mArgs
.as
<WorkerFetchArgs
>();
223 mFetchDriver
->SetWorkerScript(args
.mWorkerScript
);
224 MOZ_ASSERT(args
.mClientInfo
.isSome());
225 mFetchDriver
->SetClientInfo(args
.mClientInfo
.ref());
226 mFetchDriver
->SetController(args
.mController
);
227 if (args
.mCSPEventListener
) {
228 mFetchDriver
->SetCSPEventListener(args
.mCSPEventListener
);
230 mFetchDriver
->SetAssociatedBrowsingContextID(
231 args
.mAssociatedBrowsingContextID
);
234 mFetchDriver
->EnableNetworkInterceptControl();
236 mPromises
= MakeRefPtr
<FetchServicePromises
>();
238 // Call FetchDriver::Fetch to start fetching.
239 // Pass AbortSignalImpl as nullptr since we no need support AbortSignalImpl
240 // with FetchService. AbortSignalImpl related information should be passed
241 // through PFetch or InterceptedHttpChannel, then call
242 // FetchService::CancelFetch() to abort the running fetch.
243 rv
= mFetchDriver
->Fetch(nullptr, this);
244 if (NS_WARN_IF(NS_FAILED(rv
))) {
246 ("FetchInstance::Fetch FetchDriver::Fetch failed(0x%X)", (uint32_t)rv
));
247 return FetchService::NetworkErrorResponse(rv
, mArgs
);
253 void FetchService::FetchInstance::Cancel() {
254 MOZ_ASSERT(XRE_IsParentProcess());
255 MOZ_ASSERT(NS_IsMainThread());
257 FETCH_LOG(("FetchInstance::Cancel() [%p]", this));
259 // If mFetchDriver is not null here, FetchInstance::Fetch() has already
260 // started, let mFetchDriver::RunAbortAlgorithm() to call
261 // FetchInstance::OnResponseEnd() to resolve the pending promises.
262 // Otherwise, resolving the pending promises here.
264 mFetchDriver
->RunAbortAlgorithm();
268 MOZ_ASSERT(mPromises
);
270 mPromises
->ResolveResponseAvailablePromise(
271 InternalResponse::NetworkError(NS_ERROR_DOM_ABORT_ERR
), __func__
);
273 mPromises
->ResolveResponseTimingPromise(ResponseTiming(), __func__
);
275 mPromises
->ResolveResponseEndPromise(
276 ResponseEndArgs(FetchDriverObserver::eAborted
), __func__
);
279 void FetchService::FetchInstance::OnResponseEnd(
280 FetchDriverObserver::EndReason aReason
,
281 JS::Handle
<JS::Value
> aReasonDetails
) {
282 FETCH_LOG(("FetchInstance::OnResponseEnd [%p] %s", this,
283 aReason
== eAborted
? "eAborted" : "eNetworking"));
285 if (mIsWorkerFetch
) {
286 FlushConsoleReport();
287 nsCOMPtr
<nsIRunnable
> r
= NS_NewRunnableFunction(
288 __func__
, [endArgs
= ResponseEndArgs(aReason
),
289 actorID
= mArgs
.as
<WorkerFetchArgs
>().mActorID
]() {
290 FETCH_LOG(("FetchInstance::OnResponseEnd, Runnable"));
291 RefPtr
<FetchParent
> actor
= FetchParent::GetActorByID(actorID
);
293 actor
->OnResponseEnd(std::move(endArgs
));
296 MOZ_ALWAYS_SUCCEEDS(mArgs
.as
<WorkerFetchArgs
>().mEventTarget
->Dispatch(
297 r
, nsIThread::DISPATCH_NORMAL
));
300 MOZ_ASSERT(mPromises
);
302 if (aReason
== eAborted
) {
303 // If ResponseAvailablePromise has not resolved yet, resolved with
304 // NS_ERROR_DOM_ABORT_ERR response.
305 if (!mPromises
->GetResponseAvailablePromise()->IsResolved()) {
306 mPromises
->ResolveResponseAvailablePromise(
307 InternalResponse::NetworkError(NS_ERROR_DOM_ABORT_ERR
), __func__
);
310 // If ResponseTimingPromise has not resolved yet, resolved with empty
312 if (!mPromises
->GetResponseTimingPromise()->IsResolved()) {
313 mPromises
->ResolveResponseTimingPromise(ResponseTiming(), __func__
);
315 // Resolve the ResponseEndPromise
316 mPromises
->ResolveResponseEndPromise(ResponseEndArgs(aReason
), __func__
);
320 MOZ_ASSERT(mPromises
->GetResponseAvailablePromise()->IsResolved() &&
321 mPromises
->GetResponseTimingPromise()->IsResolved());
323 // Resolve the ResponseEndPromise
324 mPromises
->ResolveResponseEndPromise(ResponseEndArgs(aReason
), __func__
);
326 // Remove the FetchInstance from FetchInstanceTable
327 RefPtr
<FetchService
> fetchService
= FetchService::GetInstance();
328 MOZ_ASSERT(fetchService
);
329 auto entry
= fetchService
->mFetchInstanceTable
.Lookup(mPromises
);
333 ("FetchInstance::OnResponseEnd entry of responsePromise[%p] is "
339 void FetchService::FetchInstance::OnResponseAvailableInternal(
340 SafeRefPtr
<InternalResponse
> aResponse
) {
341 FETCH_LOG(("FetchInstance::OnResponseAvailableInternal [%p]", this));
342 mResponse
= std::move(aResponse
);
344 nsCOMPtr
<nsIInputStream
> body
;
345 mResponse
->GetUnfilteredBody(getter_AddRefs(body
));
347 ("FetchInstance::OnResponseAvailableInternal [%p] response body: %p",
350 if (mIsWorkerFetch
) {
351 nsCOMPtr
<nsIRunnable
> r
= NS_NewRunnableFunction(
352 __func__
, [response
= mResponse
.clonePtr(),
353 actorID
= mArgs
.as
<WorkerFetchArgs
>().mActorID
]() mutable {
354 FETCH_LOG(("FetchInstance::OnResponseAvailableInternal Runnable"));
355 RefPtr
<FetchParent
> actor
= FetchParent::GetActorByID(actorID
);
357 actor
->OnResponseAvailableInternal(std::move(response
));
360 MOZ_ALWAYS_SUCCEEDS(mArgs
.as
<WorkerFetchArgs
>().mEventTarget
->Dispatch(
361 r
, nsIThread::DISPATCH_NORMAL
));
364 MOZ_ASSERT(mPromises
);
366 // Resolve the ResponseAvailablePromise
367 mPromises
->ResolveResponseAvailablePromise(mResponse
.clonePtr(), __func__
);
370 bool FetchService::FetchInstance::NeedOnDataAvailable() {
371 if (mArgs
.is
<WorkerFetchArgs
>()) {
372 return mArgs
.as
<WorkerFetchArgs
>().mNeedOnDataAvailable
;
377 void FetchService::FetchInstance::OnDataAvailable() {
378 FETCH_LOG(("FetchInstance::OnDataAvailable [%p]", this));
380 if (!NeedOnDataAvailable()) {
384 if (mIsWorkerFetch
) {
385 nsCOMPtr
<nsIRunnable
> r
= NS_NewRunnableFunction(
386 __func__
, [actorID
= mArgs
.as
<WorkerFetchArgs
>().mActorID
]() {
387 FETCH_LOG(("FetchInstance::OnDataAvailable, Runnable"));
388 RefPtr
<FetchParent
> actor
= FetchParent::GetActorByID(actorID
);
390 actor
->OnDataAvailable();
393 MOZ_ALWAYS_SUCCEEDS(mArgs
.as
<WorkerFetchArgs
>().mEventTarget
->Dispatch(
394 r
, nsIThread::DISPATCH_NORMAL
));
398 void FetchService::FetchInstance::FlushConsoleReport() {
399 FETCH_LOG(("FetchInstance::FlushConsoleReport [%p]", this));
401 if (mIsWorkerFetch
) {
405 nsTArray
<net::ConsoleReportCollected
> reports
;
406 mReporter
->StealConsoleReports(reports
);
407 nsCOMPtr
<nsIRunnable
> r
= NS_NewRunnableFunction(
408 __func__
, [actorID
= mArgs
.as
<WorkerFetchArgs
>().mActorID
,
409 consoleReports
= std::move(reports
)]() {
410 FETCH_LOG(("FetchInstance::FlushConsolReport, Runnable"));
411 RefPtr
<FetchParent
> actor
= FetchParent::GetActorByID(actorID
);
413 actor
->OnFlushConsoleReport(std::move(consoleReports
));
416 MOZ_ALWAYS_SUCCEEDS(mArgs
.as
<WorkerFetchArgs
>().mEventTarget
->Dispatch(
417 r
, nsIThread::DISPATCH_NORMAL
));
421 void FetchService::FetchInstance::OnReportPerformanceTiming() {
422 FETCH_LOG(("FetchInstance::OnReportPerformanceTiming [%p]", this));
423 MOZ_ASSERT(mFetchDriver
);
424 MOZ_ASSERT(mPromises
);
426 if (mPromises
->GetResponseTimingPromise()->IsResolved()) {
430 ResponseTiming timing
;
431 UniquePtr
<PerformanceTimingData
> performanceTiming(
432 mFetchDriver
->GetPerformanceTimingData(timing
.initiatorType(),
433 timing
.entryName()));
434 // FetchDriver has no corresponding performance timing when fetch() failed.
435 // Resolve the ResponseTimingPromise with empty timing.
436 if (!performanceTiming
) {
437 mPromises
->ResolveResponseTimingPromise(ResponseTiming(), __func__
);
440 timing
.timingData() = performanceTiming
->ToIPC();
441 // Force replace initiatorType for ServiceWorkerNavgationPreload.
442 if (!mIsWorkerFetch
) {
443 timing
.initiatorType() = u
"navigation"_ns
;
445 nsCOMPtr
<nsIRunnable
> r
= NS_NewRunnableFunction(
447 [actorID
= mArgs
.as
<WorkerFetchArgs
>().mActorID
, timing
= timing
]() {
448 FETCH_LOG(("FetchInstance::OnReportPerformanceTiming, Runnable"));
449 RefPtr
<FetchParent
> actor
= FetchParent::GetActorByID(actorID
);
451 actor
->OnReportPerformanceTiming(std::move(timing
));
454 MOZ_ALWAYS_SUCCEEDS(mArgs
.as
<WorkerFetchArgs
>().mEventTarget
->Dispatch(
455 r
, nsIThread::DISPATCH_NORMAL
));
458 mPromises
->ResolveResponseTimingPromise(std::move(timing
), __func__
);
461 void FetchService::FetchInstance::OnNotifyNetworkMonitorAlternateStack(
462 uint64_t aChannelID
) {
463 FETCH_LOG(("FetchInstance::OnNotifyNetworkMonitorAlternateStack [%p]", this));
464 MOZ_ASSERT(mFetchDriver
);
465 MOZ_ASSERT(mPromises
);
466 if (!mIsWorkerFetch
) {
470 nsCOMPtr
<nsIRunnable
> r
= NS_NewRunnableFunction(
471 __func__
, [actorID
= mArgs
.as
<WorkerFetchArgs
>().mActorID
,
472 channelID
= aChannelID
]() {
474 ("FetchInstance::NotifyNetworkMonitorAlternateStack, Runnable"));
475 RefPtr
<FetchParent
> actor
= FetchParent::GetActorByID(actorID
);
477 actor
->OnNotifyNetworkMonitorAlternateStack(channelID
);
481 MOZ_ALWAYS_SUCCEEDS(mArgs
.as
<WorkerFetchArgs
>().mEventTarget
->Dispatch(
482 r
, nsIThread::DISPATCH_NORMAL
));
487 NS_IMPL_ISUPPORTS(FetchService
, nsIObserver
)
489 StaticRefPtr
<FetchService
> gInstance
;
492 already_AddRefed
<FetchService
> FetchService::GetInstance() {
493 MOZ_ASSERT(XRE_IsParentProcess());
494 MOZ_ASSERT(NS_IsMainThread());
497 gInstance
= MakeRefPtr
<FetchService
>();
498 nsresult rv
= gInstance
->RegisterNetworkObserver();
499 if (NS_WARN_IF(NS_FAILED(rv
))) {
503 ClearOnShutdown(&gInstance
);
505 RefPtr
<FetchService
> service
= gInstance
;
506 return service
.forget();
510 RefPtr
<FetchServicePromises
> FetchService::NetworkErrorResponse(
511 nsresult aRv
, const FetchArgs
& aArgs
) {
512 if (aArgs
.is
<WorkerFetchArgs
>()) {
513 const WorkerFetchArgs
& args
= aArgs
.as
<WorkerFetchArgs
>();
514 nsCOMPtr
<nsIRunnable
> r
= NS_NewRunnableFunction(
515 __func__
, [aRv
, actorID
= args
.mActorID
]() mutable {
517 ("FetchService::PropagateErrorResponse runnable aError: 0x%X",
519 RefPtr
<FetchParent
> actor
= FetchParent::GetActorByID(actorID
);
521 actor
->OnResponseAvailableInternal(
522 InternalResponse::NetworkError(aRv
));
523 actor
->OnResponseEnd(
524 ResponseEndArgs(FetchDriverObserver::eAborted
));
528 args
.mEventTarget
->Dispatch(r
, nsIThread::DISPATCH_NORMAL
));
531 RefPtr
<FetchServicePromises
> promises
= MakeRefPtr
<FetchServicePromises
>();
532 promises
->ResolveResponseAvailablePromise(InternalResponse::NetworkError(aRv
),
534 promises
->ResolveResponseTimingPromise(ResponseTiming(), __func__
);
535 promises
->ResolveResponseEndPromise(
536 ResponseEndArgs(FetchDriverObserver::eAborted
), __func__
);
540 FetchService::FetchService() {
541 MOZ_ASSERT(XRE_IsParentProcess());
542 MOZ_ASSERT(NS_IsMainThread());
545 FetchService::~FetchService() {
546 MOZ_ALWAYS_SUCCEEDS(UnregisterNetworkObserver());
549 nsresult
FetchService::RegisterNetworkObserver() {
550 AssertIsOnMainThread();
551 nsCOMPtr
<nsIObserverService
> observerService
= services::GetObserverService();
552 if (!observerService
) {
553 return NS_ERROR_UNEXPECTED
;
556 nsCOMPtr
<nsIIOService
> ioService
= services::GetIOService();
558 return NS_ERROR_UNEXPECTED
;
561 nsresult rv
= observerService
->AddObserver(
562 this, NS_IOSERVICE_OFFLINE_STATUS_TOPIC
, false);
563 NS_ENSURE_SUCCESS(rv
, rv
);
565 rv
= observerService
->AddObserver(this, "xpcom-shutdown", false);
566 NS_ENSURE_SUCCESS(rv
, rv
);
568 rv
= ioService
->GetOffline(&mOffline
);
569 NS_ENSURE_SUCCESS(rv
, rv
);
570 mObservingNetwork
= true;
575 nsresult
FetchService::UnregisterNetworkObserver() {
576 AssertIsOnMainThread();
578 if (mObservingNetwork
) {
579 nsCOMPtr
<nsIObserverService
> observerService
=
580 mozilla::services::GetObserverService();
581 if (observerService
) {
582 rv
= observerService
->RemoveObserver(this,
583 NS_IOSERVICE_OFFLINE_STATUS_TOPIC
);
584 NS_ENSURE_SUCCESS(rv
, rv
);
585 rv
= observerService
->RemoveObserver(this, "xpcom-shutdown");
586 NS_ENSURE_SUCCESS(rv
, rv
);
588 mObservingNetwork
= false;
593 NS_IMETHODIMP
FetchService::Observe(nsISupports
* aSubject
, const char* aTopic
,
594 const char16_t
* aData
) {
595 FETCH_LOG(("FetchService::Observe topic: %s", aTopic
));
596 AssertIsOnMainThread();
597 MOZ_ASSERT(!strcmp(aTopic
, NS_IOSERVICE_OFFLINE_STATUS_TOPIC
) ||
598 !strcmp(aTopic
, "xpcom-shutdown"));
600 if (!strcmp(aTopic
, "xpcom-shutdown")) {
601 // Going to shutdown, unregister the network status observer to avoid
603 nsresult rv
= UnregisterNetworkObserver();
604 NS_ENSURE_SUCCESS(rv
, rv
);
608 if (nsDependentString(aData
).EqualsLiteral(NS_IOSERVICE_ONLINE
)) {
612 // Network is offline, cancel running fetchs.
613 for (auto it
= mFetchInstanceTable
.begin(), end
= mFetchInstanceTable
.end();
615 it
->GetData()->Cancel();
617 mFetchInstanceTable
.Clear();
622 RefPtr
<FetchServicePromises
> FetchService::Fetch(FetchArgs
&& aArgs
) {
623 MOZ_ASSERT(XRE_IsParentProcess());
624 MOZ_ASSERT(NS_IsMainThread());
626 FETCH_LOG(("FetchService::Fetch (%s)", aArgs
.is
<NavigationPreloadArgs
>()
627 ? "NavigationPreload"
630 FETCH_LOG(("FetchService::Fetch network offline"));
631 return NetworkErrorResponse(NS_ERROR_OFFLINE
, aArgs
);
634 // Create FetchInstance
635 RefPtr
<FetchInstance
> fetch
= MakeRefPtr
<FetchInstance
>();
637 // Call FetchInstance::Initialize() to get needed information for FetchDriver
638 nsresult rv
= fetch
->Initialize(std::move(aArgs
));
639 if (NS_WARN_IF(NS_FAILED(rv
))) {
640 return NetworkErrorResponse(rv
, fetch
->Args());
643 // Call FetchInstance::Fetch() to start an asynchronous fetching.
644 RefPtr
<FetchServicePromises
> promises
= fetch
->Fetch();
645 MOZ_ASSERT(promises
);
647 if (!promises
->GetResponseAvailablePromise()->IsResolved()) {
648 // Insert the created FetchInstance into FetchInstanceTable.
649 if (!mFetchInstanceTable
.WithEntryHandle(promises
, [&](auto&& entry
) {
650 if (entry
.HasEntry()) {
657 ("FetchService::Fetch entry[%p] already exists", promises
.get()));
658 return NetworkErrorResponse(NS_ERROR_UNEXPECTED
, fetch
->Args());
660 FETCH_LOG(("FetchService::Fetch entry[%p] of FetchInstance[%p] added",
661 promises
.get(), fetch
.get()));
666 void FetchService::CancelFetch(const RefPtr
<FetchServicePromises
>&& aPromises
) {
667 MOZ_ASSERT(XRE_IsParentProcess());
668 MOZ_ASSERT(NS_IsMainThread());
669 MOZ_ASSERT(aPromises
);
670 FETCH_LOG(("FetchService::CancelFetch aPromises[%p]", aPromises
.get()));
672 auto entry
= mFetchInstanceTable
.Lookup(aPromises
);
674 // Notice any modifications here before entry.Remove() probably should be
675 // reflected to Observe() offline case.
676 entry
.Data()->Cancel();
679 ("FetchService::CancelFetch entry [%p] removed", aPromises
.get()));
683 } // namespace mozilla::dom