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 "FetchService.h"
8 #include "InternalRequest.h"
9 #include "InternalResponse.h"
10 #include "mozilla/Unused.h"
11 #include "mozilla/dom/ClientInfo.h"
12 #include "mozilla/dom/FetchTypes.h"
13 #include "mozilla/dom/PerformanceTimingTypes.h"
14 #include "mozilla/dom/ServiceWorkerDescriptor.h"
15 #include "mozilla/ipc/BackgroundParent.h"
16 #include "nsThreadUtils.h"
18 using namespace mozilla::ipc
;
20 namespace mozilla::dom
{
22 NS_IMPL_ISUPPORTS(FetchParent::FetchParentCSPEventListener
, nsICSPEventListener
)
24 FetchParent::FetchParentCSPEventListener::FetchParentCSPEventListener(
25 const nsID
& aActorID
, nsCOMPtr
<nsISerialEventTarget
> aEventTarget
)
26 : mActorID(aActorID
), mEventTarget(aEventTarget
) {
27 MOZ_ASSERT(mEventTarget
);
28 FETCH_LOG(("FetchParentCSPEventListener [%p] actor ID: %s", this,
29 mActorID
.ToString().get()));
32 NS_IMETHODIMP
FetchParent::FetchParentCSPEventListener::OnCSPViolationEvent(
33 const nsAString
& aJSON
) {
34 AssertIsOnMainThread();
35 FETCH_LOG(("FetchParentCSPEventListener::OnCSPViolationEvent [%p]", this));
37 nsAutoString
json(aJSON
);
38 nsCOMPtr
<nsIRunnable
> r
=
39 NS_NewRunnableFunction(__func__
, [actorID
= mActorID
, json
]() mutable {
41 ("FetchParentCSPEventListener::OnCSPViolationEvent, Runnale"));
42 RefPtr
<FetchParent
> actor
= FetchParent::GetActorByID(actorID
);
44 actor
->OnCSPViolationEvent(json
);
48 MOZ_ALWAYS_SUCCEEDS(mEventTarget
->Dispatch(r
, nsIThread::DISPATCH_NORMAL
));
52 MOZ_RUNINIT nsTHashMap
<nsIDHashKey
, RefPtr
<FetchParent
>>
53 FetchParent::sActorTable
;
56 RefPtr
<FetchParent
> FetchParent::GetActorByID(const nsID
& aID
) {
57 AssertIsOnBackgroundThread();
58 auto entry
= sActorTable
.Lookup(aID
);
65 FetchParent::FetchParent() : mID(nsID::GenerateUUID()) {
66 FETCH_LOG(("FetchParent::FetchParent [%p]", this));
67 AssertIsOnBackgroundThread();
68 mBackgroundEventTarget
= GetCurrentSerialEventTarget();
69 MOZ_ASSERT(mBackgroundEventTarget
);
70 if (!sActorTable
.WithEntryHandle(mID
, [&](auto&& entry
) {
71 if (entry
.HasEntry()) {
77 FETCH_LOG(("FetchParent::FetchParent entry[%p] already exists", this));
81 FetchParent::~FetchParent() {
82 FETCH_LOG(("FetchParent::~FetchParent [%p]", this));
83 // MOZ_ASSERT(!mBackgroundEventTarget);
84 MOZ_ASSERT(mActorDestroyed
&& mIsDone
);
85 mResponsePromises
= nullptr;
88 IPCResult
FetchParent::RecvFetchOp(FetchOpArgs
&& aArgs
) {
89 FETCH_LOG(("FetchParent::RecvFetchOp [%p]", this));
90 AssertIsOnBackgroundThread();
93 if (mActorDestroyed
) {
97 mRequest
= MakeSafeRefPtr
<InternalRequest
>(std::move(aArgs
.request()));
98 mIsWorkerFetch
= aArgs
.isWorkerRequest();
99 mPrincipalInfo
= std::move(aArgs
.principalInfo());
100 mWorkerScript
= aArgs
.workerScript();
101 mClientInfo
= Some(ClientInfo(aArgs
.clientInfo()));
102 if (aArgs
.controller().isSome()) {
103 mController
= Some(ServiceWorkerDescriptor(aArgs
.controller().ref()));
105 mCookieJarSettings
= aArgs
.cookieJarSettings();
106 mNeedOnDataAvailable
= aArgs
.needOnDataAvailable();
107 mHasCSPEventListener
= aArgs
.hasCSPEventListener();
108 mIsThirdPartyContext
= aArgs
.isThirdPartyContext();
109 mIsOn3PCBExceptionList
= aArgs
.isOn3PCBExceptionList();
111 if (mHasCSPEventListener
) {
113 MakeRefPtr
<FetchParentCSPEventListener
>(mID
, mBackgroundEventTarget
);
115 mAssociatedBrowsingContextID
= aArgs
.associatedBrowsingContextID();
117 MOZ_ASSERT(!mPromise
);
118 mPromise
= new GenericPromise::Private(__func__
);
120 RefPtr
<FetchParent
> self
= this;
122 mBackgroundEventTarget
, __func__
,
123 [self
](const bool&& result
) mutable {
125 ("FetchParent::RecvFetchOp [%p] Success Callback", self
.get()));
126 AssertIsOnBackgroundThread();
127 self
->mPromise
= nullptr;
129 FETCH_LOG(("FetchParent::RecvFetchOp [%p] Fetch has already aborted",
131 if (!self
->mActorDestroyed
) {
132 Unused
<< NS_WARN_IF(
133 !self
->Send__delete__(self
, NS_ERROR_DOM_ABORT_ERR
));
137 self
->mIsDone
= true;
138 if (!self
->mActorDestroyed
&& !self
->mExtendForCSPEventListener
) {
139 FETCH_LOG(("FetchParent::RecvFetchOp [%p] Send__delete__(NS_OK)",
141 Unused
<< NS_WARN_IF(!self
->Send__delete__(self
, NS_OK
));
144 [self
](const nsresult
&& aErr
) mutable {
146 ("FetchParent::RecvFetchOp [%p] Failure Callback", self
.get()));
147 AssertIsOnBackgroundThread();
148 self
->mIsDone
= true;
149 self
->mPromise
= nullptr;
150 if (!self
->mActorDestroyed
) {
151 FETCH_LOG(("FetchParent::RecvFetchOp [%p] Send__delete__(aErr)",
153 Unused
<< NS_WARN_IF(!self
->Send__delete__(self
, aErr
));
157 RefPtr
<nsIRunnable
> r
= NS_NewRunnableFunction(__func__
, [self
]() mutable {
159 ("FetchParent::RecvFetchOp [%p], Main Thread Runnable", self
.get()));
160 AssertIsOnMainThread();
162 MOZ_ASSERT(!self
->mResponsePromises
);
163 MOZ_ASSERT(self
->mPromise
);
165 ("FetchParent::RecvFetchOp [%p], Main Thread Runnable, "
168 self
->mPromise
->Reject(NS_ERROR_DOM_ABORT_ERR
, __func__
);
171 RefPtr
<FetchService
> fetchService
= FetchService::GetInstance();
172 MOZ_ASSERT(fetchService
);
173 MOZ_ASSERT(self
->mRequest
);
174 MOZ_ASSERT(!self
->mResponsePromises
);
175 if (self
->mIsWorkerFetch
) {
176 self
->mResponsePromises
=
177 fetchService
->Fetch(AsVariant(FetchService::WorkerFetchArgs(
178 {self
->mRequest
.clonePtr(), self
->mPrincipalInfo
,
179 self
->mWorkerScript
, self
->mClientInfo
, self
->mController
,
180 self
->mCookieJarSettings
, self
->mNeedOnDataAvailable
,
181 self
->mCSPEventListener
, self
->mAssociatedBrowsingContextID
,
182 self
->mBackgroundEventTarget
, self
->mID
,
183 self
->mIsThirdPartyContext
,
184 MozPromiseRequestHolder
<FetchServiceResponseEndPromise
>(),
185 self
->mPromise
, self
->mIsOn3PCBExceptionList
})));
187 MOZ_ASSERT(self
->mRequest
->GetKeepalive());
188 self
->mResponsePromises
=
189 fetchService
->Fetch(AsVariant(FetchService::MainThreadFetchArgs({
190 self
->mRequest
.clonePtr(),
191 self
->mPrincipalInfo
,
192 self
->mCookieJarSettings
,
193 self
->mNeedOnDataAvailable
,
194 self
->mCSPEventListener
,
195 self
->mAssociatedBrowsingContextID
,
196 self
->mBackgroundEventTarget
,
198 self
->mIsThirdPartyContext
,
203 self
->mResponsePromises
->GetResponseEndPromise()->IsResolved();
204 if (!isResolved
&& self
->mIsWorkerFetch
) {
205 // track only unresolved promises for worker fetch requests
206 // this is needed for clean-up of keepalive requests
207 self
->mResponsePromises
->GetResponseEndPromise()
209 GetMainThreadSerialEventTarget(), __func__
,
210 [self
](ResponseEndArgs
&& aArgs
) mutable {
211 AssertIsOnMainThread();
212 MOZ_ASSERT(self
->mPromise
);
213 self
->mPromise
->Resolve(true, __func__
);
214 self
->mResponsePromises
= nullptr;
216 [self
](CopyableErrorResult
&& aErr
) mutable {
217 AssertIsOnMainThread();
218 MOZ_ASSERT(self
->mPromise
);
219 self
->mPromise
->Reject(aErr
.StealNSResult(), __func__
);
220 self
->mResponsePromises
= nullptr;
222 ->Track(fetchService
->GetResponseEndPromiseHolder(
223 self
->mResponsePromises
));
225 self
->mResponsePromises
->GetResponseEndPromise()->Then(
226 GetMainThreadSerialEventTarget(), __func__
,
227 [self
](ResponseEndArgs
&& aArgs
) mutable {
228 AssertIsOnMainThread();
229 MOZ_ASSERT(self
->mPromise
);
230 self
->mPromise
->Resolve(true, __func__
);
231 self
->mResponsePromises
= nullptr;
233 [self
](CopyableErrorResult
&& aErr
) mutable {
234 AssertIsOnMainThread();
235 MOZ_ASSERT(self
->mPromise
);
236 self
->mPromise
->Reject(aErr
.StealNSResult(), __func__
);
237 self
->mResponsePromises
= nullptr;
243 NS_DispatchToMainThread(r
.forget(), nsIThread::DISPATCH_NORMAL
));
248 IPCResult
FetchParent::RecvAbortFetchOp(bool aForceAbort
) {
249 FETCH_LOG(("FetchParent::RecvAbortFetchOp [%p]", this));
250 AssertIsOnBackgroundThread();
253 FETCH_LOG(("FetchParent::RecvAbortFetchOp [%p], Already aborted", this));
257 if (!aForceAbort
&& mRequest
&& mRequest
->GetKeepalive()) {
258 // Keeping FetchParent/FetchChild alive for the main-thread keepalive fetch
259 // here is a temporary solution. The cancel logic should always be handled
260 // in FetchInstance::Cancel() once all main-thread fetch routing through
262 if (!mIsWorkerFetch
) {
263 FETCH_LOG(("Skip aborting fetch as the request is marked keepalive"));
269 RefPtr
<FetchParent
> self
= this;
270 nsCOMPtr
<nsIRunnable
> r
= NS_NewRunnableFunction(
271 __func__
, [self
, forceAbort
= aForceAbort
]() mutable {
272 FETCH_LOG(("FetchParent::RecvAbortFetchOp Runnable"));
273 AssertIsOnMainThread();
274 if (self
->mResponsePromises
) {
275 RefPtr
<FetchService
> fetchService
= FetchService::GetInstance();
276 MOZ_ASSERT(fetchService
);
277 fetchService
->CancelFetch(std::move(self
->mResponsePromises
),
283 NS_DispatchToMainThread(r
.forget(), nsIThread::DISPATCH_NORMAL
));
288 void FetchParent::OnResponseAvailableInternal(
289 SafeRefPtr
<InternalResponse
>&& aResponse
) {
290 FETCH_LOG(("FetchParent::OnResponseAvailableInternal [%p]", this));
291 AssertIsOnBackgroundThread();
292 MOZ_ASSERT(aResponse
);
293 MOZ_ASSERT(!mActorDestroyed
);
295 if (mIsDone
&& aResponse
->Type() != ResponseType::Error
) {
297 ("FetchParent::OnResponseAvailableInternal [%p] "
298 "Fetch has already aborted",
303 // To monitor the stream status between processes, response's body can not
304 // be serialized as RemoteLazyInputStream. Such that stream close can be
305 // propagated to FetchDriver in the parent process.
306 aResponse
->SetSerializeAsLazy(false);
308 // CSP violation notification is asynchronous. Extending the FetchParent's
309 // life cycle for the notificaiton.
310 if (aResponse
->Type() == ResponseType::Error
&&
311 aResponse
->GetErrorCode() == NS_ERROR_CONTENT_BLOCKED
&&
314 ("FetchParent::OnResponseAvailableInternal [%p] "
315 "NS_ERROR_CONTENT_BLOCKED",
317 mExtendForCSPEventListener
= true;
320 Unused
<< SendOnResponseAvailableInternal(
321 aResponse
->ToParentToChildInternalResponse());
324 void FetchParent::OnResponseEnd(const ResponseEndArgs
& aArgs
) {
325 FETCH_LOG(("FetchParent::OnResponseEnd [%p]", this));
326 AssertIsOnBackgroundThread();
327 MOZ_ASSERT(!mActorDestroyed
);
329 if (mIsDone
&& aArgs
.endReason() != FetchDriverObserver::eAborted
) {
331 ("FetchParent::OnResponseEnd [%p] "
332 "Fetch has already aborted",
337 Unused
<< SendOnResponseEnd(aArgs
);
340 void FetchParent::OnDataAvailable() {
341 FETCH_LOG(("FetchParent::OnDataAvailable [%p]", this));
342 AssertIsOnBackgroundThread();
343 MOZ_ASSERT(!mActorDestroyed
);
345 Unused
<< SendOnDataAvailable();
348 void FetchParent::OnFlushConsoleReport(
349 const nsTArray
<net::ConsoleReportCollected
>& aReports
) {
350 FETCH_LOG(("FetchParent::OnFlushConsoleReport [%p]", this));
351 AssertIsOnBackgroundThread();
352 MOZ_ASSERT(!mActorDestroyed
);
354 Unused
<< SendOnFlushConsoleReport(aReports
);
357 void FetchParent::OnReportPerformanceTiming(const ResponseTiming
&& aTiming
) {
358 FETCH_LOG(("FetchParent::OnReportPerformanceTiming [%p]", this));
359 AssertIsOnBackgroundThread();
360 MOZ_ASSERT(!mActorDestroyed
);
362 Unused
<< SendOnReportPerformanceTiming(aTiming
);
365 void FetchParent::OnNotifyNetworkMonitorAlternateStack(uint64_t aChannelID
) {
366 FETCH_LOG(("FetchParent::OnNotifyNetworkMonitorAlternateStack [%p]", this));
367 AssertIsOnBackgroundThread();
368 MOZ_ASSERT(!mActorDestroyed
);
370 Unused
<< SendOnNotifyNetworkMonitorAlternateStack(aChannelID
);
373 void FetchParent::ActorDestroy(ActorDestroyReason aReason
) {
374 FETCH_LOG(("FetchParent::ActorDestroy [%p]", this));
375 AssertIsOnBackgroundThread();
376 mActorDestroyed
= true;
377 auto entry
= sActorTable
.Lookup(mID
);
380 FETCH_LOG(("FetchParent::ActorDestroy entry [%p] removed", this));
382 // mRequest can be null when FetchParent has not yet received RecvFetchOp()
387 // Abort the existing fetch.
388 // Actor can be destoried by shutdown when still fetching.
389 RecvAbortFetchOp(false);
391 // mBackgroundEventTarget = nullptr;
394 nsICSPEventListener
* FetchParent::GetCSPEventListener() {
395 return mCSPEventListener
;
398 void FetchParent::OnCSPViolationEvent(const nsAString
& aJSON
) {
399 FETCH_LOG(("FetchParent::OnCSPViolationEvent [%p]", this));
400 AssertIsOnBackgroundThread();
401 MOZ_ASSERT(mHasCSPEventListener
);
402 MOZ_ASSERT(!mActorDestroyed
);
404 Unused
<< SendOnCSPViolationEvent(aJSON
);
407 } // namespace mozilla::dom