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/. */
5 #include "FetchChild.h"
7 #include "FetchObserver.h"
8 #include "InternalResponse.h"
11 #include "mozilla/ConsoleReportCollector.h"
12 #include "mozilla/SchedulerGroup.h"
13 #include "mozilla/dom/PerformanceTiming.h"
14 #include "mozilla/dom/PerformanceStorage.h"
15 #include "mozilla/dom/Promise.h"
16 #include "mozilla/dom/RemoteWorkerChild.h"
17 #include "mozilla/dom/SecurityPolicyViolationEventBinding.h"
18 #include "mozilla/dom/WorkerChannelInfo.h"
19 #include "mozilla/dom/WorkerPrivate.h"
20 #include "mozilla/dom/WorkerRef.h"
21 #include "mozilla/dom/WorkerScope.h"
22 #include "nsIAsyncInputStream.h"
23 #include "nsIGlobalObject.h"
24 #include "nsIObserverService.h"
25 #include "nsIRunnable.h"
27 #include "nsNetUtil.h"
28 #include "nsThreadUtils.h"
30 namespace mozilla::dom
{
32 NS_IMPL_ISUPPORTS0(FetchChild
)
34 mozilla::ipc::IPCResult
FetchChild::Recv__delete__(const nsresult
&& aResult
) {
35 FETCH_LOG(("FetchChild::Recv__delete__ [%p]", this));
39 // Shutdown has not been called, so mWorkerRef->Private() should be still
41 MOZ_ASSERT(mWorkerRef
->Private());
42 mWorkerRef
->Private()->AssertIsOnWorkerThread();
44 if (mPromise
->State() == Promise::PromiseState::Pending
) {
45 if (NS_FAILED(aResult
)) {
46 mPromise
->MaybeReject(aResult
);
48 mFetchObserver
->SetState(FetchState::Errored
);
51 mPromise
->MaybeResolve(aResult
);
53 mFetchObserver
->SetState(FetchState::Complete
);
60 mozilla::ipc::IPCResult
FetchChild::RecvOnResponseAvailableInternal(
61 ParentToChildInternalResponse
&& aResponse
) {
62 FETCH_LOG(("FetchChild::RecvOnResponseAvailableInternal [%p]", this));
66 // Shutdown has not been called, so mWorkerRef->Private() should be still
68 MOZ_ASSERT(mWorkerRef
->Private());
69 mWorkerRef
->Private()->AssertIsOnWorkerThread();
70 SafeRefPtr
<InternalResponse
> internalResponse
=
71 InternalResponse::FromIPC(aResponse
);
72 IgnoredErrorResult result
;
73 internalResponse
->Headers()->SetGuard(HeadersGuardEnum::Immutable
, result
);
74 MOZ_ASSERT(internalResponse
);
76 if (internalResponse
->Type() != ResponseType::Error
) {
77 if (internalResponse
->Type() == ResponseType::Opaque
) {
78 internalResponse
->GeneratePaddingInfo();
82 mFetchObserver
->SetState(FetchState::Complete
);
84 nsCOMPtr
<nsIGlobalObject
> global
;
85 global
= mWorkerRef
->Private()->GlobalScope();
86 RefPtr
<Response
> response
=
87 new Response(global
, internalResponse
.clonePtr(), mSignalImpl
);
88 mPromise
->MaybeResolve(response
);
94 ("FetchChild::RecvOnResponseAvailableInternal [%p] response type is "
96 this, static_cast<int32_t>(internalResponse
->GetErrorCode())));
98 mFetchObserver
->SetState(FetchState::Errored
);
100 mPromise
->MaybeRejectWithTypeError
<MSG_FETCH_FAILED
>();
104 mozilla::ipc::IPCResult
FetchChild::RecvOnResponseEnd(ResponseEndArgs
&& aArgs
) {
105 FETCH_LOG(("FetchChild::RecvOnResponseEnd [%p]", this));
109 // Shutdown has not been called, so mWorkerRef->Private() should be still
111 MOZ_ASSERT(mWorkerRef
->Private());
112 mWorkerRef
->Private()->AssertIsOnWorkerThread();
114 if (aArgs
.endReason() == FetchDriverObserver::eAborted
) {
116 ("FetchChild::RecvOnResponseEnd [%p] endReason is eAborted", this));
117 if (mFetchObserver
) {
118 mFetchObserver
->SetState(FetchState::Errored
);
120 mPromise
->MaybeReject(NS_ERROR_DOM_ABORT_ERR
);
127 mozilla::ipc::IPCResult
FetchChild::RecvOnDataAvailable() {
128 FETCH_LOG(("FetchChild::RecvOnDataAvailable [%p]", this));
132 // Shutdown has not been called, so mWorkerRef->Private() should be still
134 MOZ_ASSERT(mWorkerRef
->Private());
135 mWorkerRef
->Private()->AssertIsOnWorkerThread();
137 if (mFetchObserver
&& mFetchObserver
->State() == FetchState::Requesting
) {
138 mFetchObserver
->SetState(FetchState::Responding
);
143 mozilla::ipc::IPCResult
FetchChild::RecvOnFlushConsoleReport(
144 nsTArray
<net::ConsoleReportCollected
>&& aReports
) {
145 FETCH_LOG(("FetchChild::RecvOnFlushConsoleReport [%p]", this));
149 // Shutdown has not been called, so mWorkerRef->Private() should be still
151 MOZ_ASSERT(mWorkerRef
->Private());
152 mWorkerRef
->Private()->AssertIsOnWorkerThread();
153 MOZ_ASSERT(mReporter
);
155 RefPtr
<ThreadSafeWorkerRef
> workerRef
= mWorkerRef
;
156 nsCOMPtr
<nsIConsoleReportCollector
> reporter
= mReporter
;
158 nsCOMPtr
<nsIRunnable
> r
= NS_NewRunnableFunction(
159 __func__
, [reports
= std::move(aReports
), reporter
= std::move(reporter
),
160 workerRef
= std::move(workerRef
)]() mutable {
161 for (const auto& report
: reports
) {
162 reporter
->AddConsoleReport(
163 report
.errorFlags(), report
.category(),
164 static_cast<nsContentUtils::PropertiesFile
>(
165 report
.propertiesFile()),
166 report
.sourceFileURI(), report
.lineNumber(),
167 report
.columnNumber(), report
.messageName(),
168 report
.stringParams());
171 if (workerRef
->Private()->IsServiceWorker()) {
172 reporter
->FlushReportsToConsoleForServiceWorkerScope(
173 workerRef
->Private()->ServiceWorkerScope());
176 if (workerRef
->Private()->IsSharedWorker()) {
178 ->GetRemoteWorkerController()
179 ->FlushReportsOnMainThread(reporter
);
182 reporter
->FlushConsoleReports(workerRef
->Private()->GetLoadGroup());
184 MOZ_ALWAYS_SUCCEEDS(SchedulerGroup::Dispatch(r
.forget()));
189 RefPtr
<FetchChild
> FetchChild::Create(WorkerPrivate
* aWorkerPrivate
,
190 RefPtr
<Promise
> aPromise
,
191 RefPtr
<AbortSignalImpl
> aSignalImpl
,
192 RefPtr
<FetchObserver
> aObserver
) {
193 MOZ_DIAGNOSTIC_ASSERT(aWorkerPrivate
);
194 aWorkerPrivate
->AssertIsOnWorkerThread();
196 RefPtr
<FetchChild
> actor
= MakeRefPtr
<FetchChild
>(
197 std::move(aPromise
), std::move(aSignalImpl
), std::move(aObserver
));
199 RefPtr
<StrongWorkerRef
> workerRef
=
200 StrongWorkerRef::Create(aWorkerPrivate
, "FetchChild", [actor
]() {
201 FETCH_LOG(("StrongWorkerRef callback"));
204 if (NS_WARN_IF(!workerRef
)) {
208 actor
->mWorkerRef
= new ThreadSafeWorkerRef(workerRef
);
209 if (NS_WARN_IF(!actor
->mWorkerRef
)) {
215 mozilla::ipc::IPCResult
FetchChild::RecvOnCSPViolationEvent(
216 const nsAString
& aJSON
) {
217 FETCH_LOG(("FetchChild::RecvOnCSPViolationEvent [%p] aJSON: %s\n", this,
218 NS_ConvertUTF16toUTF8(aJSON
).BeginReading()));
220 nsString
JSON(aJSON
);
222 nsCOMPtr
<nsIRunnable
> r
= NS_NewRunnableFunction(__func__
, [JSON
]() mutable {
223 SecurityPolicyViolationEventInit violationEventInit
;
224 if (NS_WARN_IF(!violationEventInit
.Init(JSON
))) {
228 nsCOMPtr
<nsIURI
> uri
;
230 NS_NewURI(getter_AddRefs(uri
), violationEventInit
.mBlockedURI
);
231 if (NS_WARN_IF(NS_FAILED(rv
))) {
235 nsCOMPtr
<nsIObserverService
> observerService
=
236 mozilla::services::GetObserverService();
237 if (!observerService
) {
241 rv
= observerService
->NotifyObservers(
242 uri
, CSP_VIOLATION_TOPIC
, violationEventInit
.mViolatedDirective
.get());
243 if (NS_WARN_IF(NS_FAILED(rv
))) {
247 MOZ_ALWAYS_SUCCEEDS(SchedulerGroup::Dispatch(r
.forget()));
249 if (mCSPEventListener
) {
250 Unused
<< NS_WARN_IF(
251 NS_FAILED(mCSPEventListener
->OnCSPViolationEvent(aJSON
)));
256 mozilla::ipc::IPCResult
FetchChild::RecvOnReportPerformanceTiming(
257 ResponseTiming
&& aTiming
) {
258 FETCH_LOG(("FetchChild::RecvOnReportPerformanceTiming [%p]", this));
262 // Shutdown has not been called, so mWorkerRef->Private() should be still
264 MOZ_ASSERT(mWorkerRef
->Private());
265 mWorkerRef
->Private()->AssertIsOnWorkerThread();
267 RefPtr
<PerformanceStorage
> performanceStorage
=
268 mWorkerRef
->Private()->GetPerformanceStorage();
269 if (performanceStorage
) {
270 performanceStorage
->AddEntry(
271 aTiming
.entryName(), aTiming
.initiatorType(),
272 MakeUnique
<PerformanceTimingData
>(aTiming
.timingData()));
277 mozilla::ipc::IPCResult
FetchChild::RecvOnNotifyNetworkMonitorAlternateStack(
278 uint64_t aChannelID
) {
280 ("FetchChild::RecvOnNotifyNetworkMonitorAlternateStack [%p]", this));
284 // Shutdown has not been called, so mWorkerRef->Private() should be still
286 MOZ_ASSERT(mWorkerRef
->Private());
287 mWorkerRef
->Private()->AssertIsOnWorkerThread();
293 if (!mWorkerChannelInfo
) {
294 mWorkerChannelInfo
= MakeRefPtr
<WorkerChannelInfo
>(
295 aChannelID
, mWorkerRef
->Private()->AssociatedBrowsingContextID());
298 // Unfortunately, SerializedStackHolder can only be read on the main thread.
299 // However, it doesn't block the fetch execution.
300 nsCOMPtr
<nsIRunnable
> r
= NS_NewRunnableFunction(
301 __func__
, [channel
= mWorkerChannelInfo
,
302 stack
= std::move(mOriginStack
)]() mutable {
303 NotifyNetworkMonitorAlternateStack(channel
, std::move(stack
));
306 MOZ_ALWAYS_SUCCEEDS(SchedulerGroup::Dispatch(r
.forget()));
311 void FetchChild::SetCSPEventListener(nsICSPEventListener
* aListener
) {
312 MOZ_ASSERT(aListener
&& !mCSPEventListener
);
313 mCSPEventListener
= aListener
;
316 FetchChild::FetchChild(RefPtr
<Promise
>&& aPromise
,
317 RefPtr
<AbortSignalImpl
>&& aSignalImpl
,
318 RefPtr
<FetchObserver
>&& aObserver
)
319 : mPromise(std::move(aPromise
)),
320 mSignalImpl(std::move(aSignalImpl
)),
321 mFetchObserver(std::move(aObserver
)),
322 mReporter(new ConsoleReportCollector()) {
323 FETCH_LOG(("FetchChild::FetchChild [%p]", this));
326 void FetchChild::RunAbortAlgorithm() {
327 FETCH_LOG(("FetchChild::RunAbortAlgorithm [%p]", this));
332 Unused
<< SendAbortFetchOp();
336 void FetchChild::DoFetchOp(const FetchOpArgs
& aArgs
) {
337 FETCH_LOG(("FetchChild::DoFetchOp [%p]", this));
339 if (mSignalImpl
->Aborted()) {
340 Unused
<< SendAbortFetchOp();
345 Unused
<< SendFetchOp(aArgs
);
348 void FetchChild::Shutdown() {
349 FETCH_LOG(("FetchChild::Shutdown [%p]", this));
355 // If mWorkerRef is nullptr here, that means Recv__delete__() must be called
360 mFetchObserver
= nullptr;
362 mSignalImpl
= nullptr;
363 mCSPEventListener
= nullptr;
364 Unused
<< SendAbortFetchOp();
365 mWorkerRef
= nullptr;
368 void FetchChild::ActorDestroy(ActorDestroyReason aReason
) {
369 FETCH_LOG(("FetchChild::ActorDestroy [%p]", this));
371 mFetchObserver
= nullptr;
372 mSignalImpl
= nullptr;
373 mCSPEventListener
= nullptr;
374 mWorkerRef
= nullptr;
377 } // namespace mozilla::dom