no bug - Bumping Firefox l10n changesets r=release a=l10n-bump DONTBUILD CLOSED TREE
[gecko.git] / dom / fetch / FetchChild.cpp
blobeff5b3ff3a2ef2943d9bb6b670bf149fb3e8100a
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"
6 #include "FetchLog.h"
7 #include "FetchObserver.h"
8 #include "InternalResponse.h"
9 #include "Request.h"
10 #include "Response.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"
26 #include "nsIURI.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));
36 if (mIsShutdown) {
37 return IPC_OK();
39 // Shutdown has not been called, so mWorkerRef->Private() should be still
40 // alive.
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);
47 if (mFetchObserver) {
48 mFetchObserver->SetState(FetchState::Errored);
50 } else {
51 mPromise->MaybeResolve(aResult);
52 if (mFetchObserver) {
53 mFetchObserver->SetState(FetchState::Complete);
57 return IPC_OK();
60 mozilla::ipc::IPCResult FetchChild::RecvOnResponseAvailableInternal(
61 ParentToChildInternalResponse&& aResponse) {
62 FETCH_LOG(("FetchChild::RecvOnResponseAvailableInternal [%p]", this));
63 if (mIsShutdown) {
64 return IPC_OK();
66 // Shutdown has not been called, so mWorkerRef->Private() should be still
67 // alive.
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();
81 if (mFetchObserver) {
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);
90 return IPC_OK();
93 FETCH_LOG(
94 ("FetchChild::RecvOnResponseAvailableInternal [%p] response type is "
95 "Error(0x%x)",
96 this, static_cast<int32_t>(internalResponse->GetErrorCode())));
97 if (mFetchObserver) {
98 mFetchObserver->SetState(FetchState::Errored);
100 mPromise->MaybeRejectWithTypeError<MSG_FETCH_FAILED>();
101 return IPC_OK();
104 mozilla::ipc::IPCResult FetchChild::RecvOnResponseEnd(ResponseEndArgs&& aArgs) {
105 FETCH_LOG(("FetchChild::RecvOnResponseEnd [%p]", this));
106 if (mIsShutdown) {
107 return IPC_OK();
109 // Shutdown has not been called, so mWorkerRef->Private() should be still
110 // alive.
111 MOZ_ASSERT(mWorkerRef->Private());
112 mWorkerRef->Private()->AssertIsOnWorkerThread();
114 if (aArgs.endReason() == FetchDriverObserver::eAborted) {
115 FETCH_LOG(
116 ("FetchChild::RecvOnResponseEnd [%p] endReason is eAborted", this));
117 if (mFetchObserver) {
118 mFetchObserver->SetState(FetchState::Errored);
120 mPromise->MaybeReject(NS_ERROR_DOM_ABORT_ERR);
123 Unfollow();
124 return IPC_OK();
127 mozilla::ipc::IPCResult FetchChild::RecvOnDataAvailable() {
128 FETCH_LOG(("FetchChild::RecvOnDataAvailable [%p]", this));
129 if (mIsShutdown) {
130 return IPC_OK();
132 // Shutdown has not been called, so mWorkerRef->Private() should be still
133 // alive.
134 MOZ_ASSERT(mWorkerRef->Private());
135 mWorkerRef->Private()->AssertIsOnWorkerThread();
137 if (mFetchObserver && mFetchObserver->State() == FetchState::Requesting) {
138 mFetchObserver->SetState(FetchState::Responding);
140 return IPC_OK();
143 mozilla::ipc::IPCResult FetchChild::RecvOnFlushConsoleReport(
144 nsTArray<net::ConsoleReportCollected>&& aReports) {
145 FETCH_LOG(("FetchChild::RecvOnFlushConsoleReport [%p]", this));
146 if (mIsShutdown) {
147 return IPC_OK();
149 // Shutdown has not been called, so mWorkerRef->Private() should be still
150 // alive.
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()) {
177 workerRef->Private()
178 ->GetRemoteWorkerController()
179 ->FlushReportsOnMainThread(reporter);
182 reporter->FlushConsoleReports(workerRef->Private()->GetLoadGroup());
184 MOZ_ALWAYS_SUCCEEDS(SchedulerGroup::Dispatch(r.forget()));
186 return IPC_OK();
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"));
202 actor->Shutdown();
204 if (NS_WARN_IF(!workerRef)) {
205 return nullptr;
208 actor->mWorkerRef = new ThreadSafeWorkerRef(workerRef);
209 if (NS_WARN_IF(!actor->mWorkerRef)) {
210 return nullptr;
212 return actor;
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))) {
225 return;
228 nsCOMPtr<nsIURI> uri;
229 nsresult rv =
230 NS_NewURI(getter_AddRefs(uri), violationEventInit.mBlockedURI);
231 if (NS_WARN_IF(NS_FAILED(rv))) {
232 return;
235 nsCOMPtr<nsIObserverService> observerService =
236 mozilla::services::GetObserverService();
237 if (!observerService) {
238 return;
241 rv = observerService->NotifyObservers(
242 uri, CSP_VIOLATION_TOPIC, violationEventInit.mViolatedDirective.get());
243 if (NS_WARN_IF(NS_FAILED(rv))) {
244 return;
247 MOZ_ALWAYS_SUCCEEDS(SchedulerGroup::Dispatch(r.forget()));
249 if (mCSPEventListener) {
250 Unused << NS_WARN_IF(
251 NS_FAILED(mCSPEventListener->OnCSPViolationEvent(aJSON)));
253 return IPC_OK();
256 mozilla::ipc::IPCResult FetchChild::RecvOnReportPerformanceTiming(
257 ResponseTiming&& aTiming) {
258 FETCH_LOG(("FetchChild::RecvOnReportPerformanceTiming [%p]", this));
259 if (mIsShutdown) {
260 return IPC_OK();
262 // Shutdown has not been called, so mWorkerRef->Private() should be still
263 // alive.
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()));
274 return IPC_OK();
277 mozilla::ipc::IPCResult FetchChild::RecvOnNotifyNetworkMonitorAlternateStack(
278 uint64_t aChannelID) {
279 FETCH_LOG(
280 ("FetchChild::RecvOnNotifyNetworkMonitorAlternateStack [%p]", this));
281 if (mIsShutdown) {
282 return IPC_OK();
284 // Shutdown has not been called, so mWorkerRef->Private() should be still
285 // alive.
286 MOZ_ASSERT(mWorkerRef->Private());
287 mWorkerRef->Private()->AssertIsOnWorkerThread();
289 if (!mOriginStack) {
290 return IPC_OK();
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()));
308 return IPC_OK();
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));
328 if (mIsShutdown) {
329 return;
331 if (mWorkerRef) {
332 Unused << SendAbortFetchOp();
336 void FetchChild::DoFetchOp(const FetchOpArgs& aArgs) {
337 FETCH_LOG(("FetchChild::DoFetchOp [%p]", this));
338 if (mSignalImpl) {
339 if (mSignalImpl->Aborted()) {
340 Unused << SendAbortFetchOp();
341 return;
343 Follow(mSignalImpl);
345 Unused << SendFetchOp(aArgs);
348 void FetchChild::Shutdown() {
349 FETCH_LOG(("FetchChild::Shutdown [%p]", this));
350 if (mIsShutdown) {
351 return;
353 mIsShutdown.Flip();
355 // If mWorkerRef is nullptr here, that means Recv__delete__() must be called
356 if (!mWorkerRef) {
357 return;
359 mPromise = nullptr;
360 mFetchObserver = nullptr;
361 Unfollow();
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));
370 mPromise = nullptr;
371 mFetchObserver = nullptr;
372 mSignalImpl = nullptr;
373 mCSPEventListener = nullptr;
374 mWorkerRef = nullptr;
377 } // namespace mozilla::dom