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 nsTHashMap
<nsIDHashKey
, RefPtr
<FetchParent
>> FetchParent::sActorTable
;
55 RefPtr
<FetchParent
> FetchParent::GetActorByID(const nsID
& aID
) {
56 AssertIsOnBackgroundThread();
57 auto entry
= sActorTable
.Lookup(aID
);
64 FetchParent::FetchParent() : mID(nsID::GenerateUUID()) {
65 FETCH_LOG(("FetchParent::FetchParent [%p]", this));
66 AssertIsOnBackgroundThread();
67 mBackgroundEventTarget
= GetCurrentSerialEventTarget();
68 MOZ_ASSERT(mBackgroundEventTarget
);
69 if (!sActorTable
.WithEntryHandle(mID
, [&](auto&& entry
) {
70 if (entry
.HasEntry()) {
76 FETCH_LOG(("FetchParent::FetchParent entry[%p] already exists", this));
80 FetchParent::~FetchParent() {
81 FETCH_LOG(("FetchParent::~FetchParent [%p]", this));
82 // MOZ_ASSERT(!mBackgroundEventTarget);
83 MOZ_ASSERT(!mResponsePromises
);
84 MOZ_ASSERT(mActorDestroyed
&& mIsDone
);
87 IPCResult
FetchParent::RecvFetchOp(FetchOpArgs
&& aArgs
) {
88 FETCH_LOG(("FetchParent::RecvFetchOp [%p]", this));
89 AssertIsOnBackgroundThread();
92 if (mActorDestroyed
) {
96 mRequest
= MakeSafeRefPtr
<InternalRequest
>(std::move(aArgs
.request()));
97 mPrincipalInfo
= std::move(aArgs
.principalInfo());
98 mWorkerScript
= aArgs
.workerScript();
99 mClientInfo
= Some(ClientInfo(aArgs
.clientInfo()));
100 if (aArgs
.controller().isSome()) {
101 mController
= Some(ServiceWorkerDescriptor(aArgs
.controller().ref()));
103 mCookieJarSettings
= aArgs
.cookieJarSettings();
104 mNeedOnDataAvailable
= aArgs
.needOnDataAvailable();
105 mHasCSPEventListener
= aArgs
.hasCSPEventListener();
107 if (mHasCSPEventListener
) {
109 MakeRefPtr
<FetchParentCSPEventListener
>(mID
, mBackgroundEventTarget
);
111 mAssociatedBrowsingContextID
= aArgs
.associatedBrowsingContextID();
113 MOZ_ASSERT(!mPromise
);
114 mPromise
= new GenericPromise::Private(__func__
);
116 RefPtr
<FetchParent
> self
= this;
118 mBackgroundEventTarget
, __func__
,
119 [self
](const bool&& result
) mutable {
121 ("FetchParent::RecvFetchOp [%p] Success Callback", self
.get()));
122 AssertIsOnBackgroundThread();
123 self
->mPromise
= nullptr;
125 FETCH_LOG(("FetchParent::RecvFetchOp [%p] Fetch has already aborted",
127 if (!self
->mActorDestroyed
) {
128 Unused
<< NS_WARN_IF(
129 !self
->Send__delete__(self
, NS_ERROR_DOM_ABORT_ERR
));
133 self
->mIsDone
= true;
134 if (!self
->mActorDestroyed
&& !self
->mExtendForCSPEventListener
) {
135 FETCH_LOG(("FetchParent::RecvFetchOp [%p] Send__delete__(NS_OK)",
137 Unused
<< NS_WARN_IF(!self
->Send__delete__(self
, NS_OK
));
140 [self
](const nsresult
&& aErr
) mutable {
142 ("FetchParent::RecvFetchOp [%p] Failure Callback", self
.get()));
143 AssertIsOnBackgroundThread();
144 self
->mIsDone
= true;
145 self
->mPromise
= nullptr;
146 if (!self
->mActorDestroyed
) {
147 FETCH_LOG(("FetchParent::RecvFetchOp [%p] Send__delete__(aErr)",
149 Unused
<< NS_WARN_IF(!self
->Send__delete__(self
, aErr
));
153 RefPtr
<nsIRunnable
> r
= NS_NewRunnableFunction(__func__
, [self
]() mutable {
155 ("FetchParent::RecvFetchOp [%p], Main Thread Runnable", self
.get()));
156 AssertIsOnMainThread();
158 MOZ_ASSERT(!self
->mResponsePromises
);
159 MOZ_ASSERT(self
->mPromise
);
161 ("FetchParent::RecvFetchOp [%p], Main Thread Runnable, "
164 self
->mPromise
->Reject(NS_ERROR_DOM_ABORT_ERR
, __func__
);
167 RefPtr
<FetchService
> fetchService
= FetchService::GetInstance();
168 MOZ_ASSERT(fetchService
);
169 MOZ_ASSERT(!self
->mResponsePromises
);
170 self
->mResponsePromises
=
171 fetchService
->Fetch(AsVariant(FetchService::WorkerFetchArgs(
172 {self
->mRequest
.clonePtr(), self
->mPrincipalInfo
,
173 self
->mWorkerScript
, self
->mClientInfo
, self
->mController
,
174 self
->mCookieJarSettings
, self
->mNeedOnDataAvailable
,
175 self
->mCSPEventListener
, self
->mAssociatedBrowsingContextID
,
176 self
->mBackgroundEventTarget
, self
->mID
})));
178 self
->mResponsePromises
->GetResponseEndPromise()->Then(
179 GetMainThreadSerialEventTarget(), __func__
,
180 [self
](ResponseEndArgs
&& aArgs
) mutable {
181 AssertIsOnMainThread();
182 MOZ_ASSERT(self
->mPromise
);
183 self
->mPromise
->Resolve(true, __func__
);
184 self
->mResponsePromises
= nullptr;
186 [self
](CopyableErrorResult
&& aErr
) mutable {
187 AssertIsOnMainThread();
188 MOZ_ASSERT(self
->mPromise
);
189 self
->mPromise
->Reject(aErr
.StealNSResult(), __func__
);
190 self
->mResponsePromises
= nullptr;
195 NS_DispatchToMainThread(r
.forget(), nsIThread::DISPATCH_NORMAL
));
200 IPCResult
FetchParent::RecvAbortFetchOp() {
201 FETCH_LOG(("FetchParent::RecvAbortFetchOp [%p]", this));
202 AssertIsOnBackgroundThread();
205 FETCH_LOG(("FetchParent::RecvAbortFetchOp [%p], Already aborted", this));
210 RefPtr
<FetchParent
> self
= this;
211 nsCOMPtr
<nsIRunnable
> r
= NS_NewRunnableFunction(__func__
, [self
]() mutable {
212 FETCH_LOG(("FetchParent::RecvAbortFetchOp Runnable"));
213 AssertIsOnMainThread();
214 if (self
->mResponsePromises
) {
215 RefPtr
<FetchService
> fetchService
= FetchService::GetInstance();
216 MOZ_ASSERT(fetchService
);
217 fetchService
->CancelFetch(std::move(self
->mResponsePromises
));
222 NS_DispatchToMainThread(r
.forget(), nsIThread::DISPATCH_NORMAL
));
227 void FetchParent::OnResponseAvailableInternal(
228 SafeRefPtr
<InternalResponse
>&& aResponse
) {
229 FETCH_LOG(("FetchParent::OnResponseAvailableInternal [%p]", this));
230 AssertIsOnBackgroundThread();
231 MOZ_ASSERT(aResponse
);
232 MOZ_ASSERT(!mActorDestroyed
);
234 if (mIsDone
&& aResponse
->Type() != ResponseType::Error
) {
236 ("FetchParent::OnResponseAvailableInternal [%p] "
237 "Fetch has already aborted",
242 // To monitor the stream status between processes, response's body can not be
243 // serialized as RemoteLazyInputStream. Such that stream close can be
244 // propagated to FetchDriver in the parent process.
245 aResponse
->SetSerializeAsLazy(false);
247 // CSP violation notification is asynchronous. Extending the FetchParent's
248 // life cycle for the notificaiton.
249 if (aResponse
->Type() == ResponseType::Error
&&
250 aResponse
->GetErrorCode() == NS_ERROR_CONTENT_BLOCKED
&&
253 ("FetchParent::OnResponseAvailableInternal [%p] "
254 "NS_ERROR_CONTENT_BLOCKED",
256 mExtendForCSPEventListener
= true;
259 Unused
<< SendOnResponseAvailableInternal(
260 aResponse
->ToParentToChildInternalResponse(WrapNotNull(Manager())));
263 void FetchParent::OnResponseEnd(const ResponseEndArgs
& aArgs
) {
264 FETCH_LOG(("FetchParent::OnResponseEnd [%p]", this));
265 AssertIsOnBackgroundThread();
266 MOZ_ASSERT(!mActorDestroyed
);
268 if (mIsDone
&& aArgs
.endReason() != FetchDriverObserver::eAborted
) {
270 ("FetchParent::OnResponseEnd [%p] "
271 "Fetch has already aborted",
276 Unused
<< SendOnResponseEnd(aArgs
);
279 void FetchParent::OnDataAvailable() {
280 FETCH_LOG(("FetchParent::OnDataAvailable [%p]", this));
281 AssertIsOnBackgroundThread();
282 MOZ_ASSERT(!mActorDestroyed
);
284 Unused
<< SendOnDataAvailable();
287 void FetchParent::OnFlushConsoleReport(
288 const nsTArray
<net::ConsoleReportCollected
>& aReports
) {
289 FETCH_LOG(("FetchParent::OnFlushConsoleReport [%p]", this));
290 AssertIsOnBackgroundThread();
291 MOZ_ASSERT(!mActorDestroyed
);
293 Unused
<< SendOnFlushConsoleReport(aReports
);
296 void FetchParent::OnReportPerformanceTiming(const ResponseTiming
&& aTiming
) {
297 FETCH_LOG(("FetchParent::OnReportPerformanceTiming [%p]", this));
298 AssertIsOnBackgroundThread();
299 MOZ_ASSERT(!mActorDestroyed
);
301 Unused
<< SendOnReportPerformanceTiming(aTiming
);
304 void FetchParent::OnNotifyNetworkMonitorAlternateStack(uint64_t aChannelID
) {
305 FETCH_LOG(("FetchParent::OnNotifyNetworkMonitorAlternateStack [%p]", this));
306 AssertIsOnBackgroundThread();
307 MOZ_ASSERT(!mActorDestroyed
);
309 Unused
<< SendOnNotifyNetworkMonitorAlternateStack(aChannelID
);
312 void FetchParent::ActorDestroy(ActorDestroyReason aReason
) {
313 FETCH_LOG(("FetchParent::ActorDestroy [%p]", this));
314 AssertIsOnBackgroundThread();
315 mActorDestroyed
= true;
316 auto entry
= sActorTable
.Lookup(mID
);
319 FETCH_LOG(("FetchParent::ActorDestroy entry [%p] removed", this));
321 // Force to abort the existing fetch.
322 // Actor can be destoried by shutdown when still fetching.
324 // mBackgroundEventTarget = nullptr;
327 nsICSPEventListener
* FetchParent::GetCSPEventListener() {
328 return mCSPEventListener
;
331 void FetchParent::OnCSPViolationEvent(const nsAString
& aJSON
) {
332 FETCH_LOG(("FetchParent::OnCSPViolationEvent [%p]", this));
333 AssertIsOnBackgroundThread();
334 MOZ_ASSERT(mHasCSPEventListener
);
335 MOZ_ASSERT(!mActorDestroyed
);
337 Unused
<< SendOnCSPViolationEvent(aJSON
);
340 } // namespace mozilla::dom