1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #include "FetchEventOpProxyParent.h"
11 #include "mozilla/dom/FetchTypes.h"
12 #include "mozilla/dom/ServiceWorkerOpArgs.h"
14 #include "nsIInputStream.h"
16 #include "mozilla/Assertions.h"
17 #include "mozilla/DebugOnly.h"
18 #include "mozilla/ResultExtensions.h"
19 #include "mozilla/Try.h"
20 #include "mozilla/UniquePtr.h"
21 #include "mozilla/Unused.h"
22 #include "mozilla/dom/InternalResponse.h"
23 #include "mozilla/dom/PRemoteWorkerParent.h"
24 #include "mozilla/dom/PRemoteWorkerControllerParent.h"
25 #include "mozilla/dom/FetchEventOpParent.h"
26 #include "mozilla/ipc/BackgroundParent.h"
27 #include "mozilla/ipc/IPCStreamUtils.h"
28 #include "mozilla/RemoteLazyInputStreamStorage.h"
38 nsresult
MaybeDeserializeAndWrapForMainThread(
39 const Maybe
<ChildToParentStream
>& aSource
, int64_t aBodyStreamSize
,
40 Maybe
<ParentToParentStream
>& aSink
, PBackgroundParent
* aManager
) {
41 if (aSource
.isNothing()) {
45 nsCOMPtr
<nsIInputStream
> deserialized
=
46 DeserializeIPCStream(aSource
->stream());
48 aSink
= Some(ParentToParentStream());
49 auto& uuid
= aSink
->uuid();
51 MOZ_TRY(nsID::GenerateUUIDInPlace(uuid
));
53 auto storageOrErr
= RemoteLazyInputStreamStorage::Get();
55 if (NS_WARN_IF(storageOrErr
.isErr())) {
56 return storageOrErr
.unwrapErr();
59 auto storage
= storageOrErr
.unwrap();
60 storage
->AddStream(deserialized
, uuid
);
64 ParentToParentInternalResponse
ToParentToParent(
65 const ChildToParentInternalResponse
& aResponse
,
66 NotNull
<PBackgroundParent
*> aBackgroundParent
) {
67 ParentToParentInternalResponse
parentToParentResponse(
68 aResponse
.metadata(), Nothing(), aResponse
.bodySize(), Nothing());
70 MOZ_ALWAYS_SUCCEEDS(MaybeDeserializeAndWrapForMainThread(
71 aResponse
.body(), aResponse
.bodySize(), parentToParentResponse
.body(),
73 MOZ_ALWAYS_SUCCEEDS(MaybeDeserializeAndWrapForMainThread(
74 aResponse
.alternativeBody(), InternalResponse::UNKNOWN_BODY_SIZE
,
75 parentToParentResponse
.alternativeBody(), aBackgroundParent
));
77 return parentToParentResponse
;
80 ParentToParentSynthesizeResponseArgs
ToParentToParent(
81 const ChildToParentSynthesizeResponseArgs
& aArgs
,
82 NotNull
<PBackgroundParent
*> aBackgroundParent
) {
83 return ParentToParentSynthesizeResponseArgs(
84 ToParentToParent(aArgs
.internalResponse(), aBackgroundParent
),
85 aArgs
.closure(), aArgs
.timeStamps());
88 ParentToParentFetchEventRespondWithResult
ToParentToParent(
89 const ChildToParentFetchEventRespondWithResult
& aResult
,
90 NotNull
<PBackgroundParent
*> aBackgroundParent
) {
91 switch (aResult
.type()) {
92 case ChildToParentFetchEventRespondWithResult::
93 TChildToParentSynthesizeResponseArgs
:
94 return ToParentToParent(aResult
.get_ChildToParentSynthesizeResponseArgs(),
97 case ChildToParentFetchEventRespondWithResult::TResetInterceptionArgs
:
98 return aResult
.get_ResetInterceptionArgs();
100 case ChildToParentFetchEventRespondWithResult::TCancelInterceptionArgs
:
101 return aResult
.get_CancelInterceptionArgs();
104 MOZ_CRASH("Invalid ParentToParentFetchEventRespondWithResult");
108 } // anonymous namespace
110 /* static */ void FetchEventOpProxyParent::Create(
111 PRemoteWorkerParent
* aManager
,
112 RefPtr
<ServiceWorkerFetchEventOpPromise::Private
>&& aPromise
,
113 const ParentToParentServiceWorkerFetchEventOpArgs
& aArgs
,
114 RefPtr
<FetchEventOpParent
> aReal
, nsCOMPtr
<nsIInputStream
> aBodyStream
) {
115 AssertIsInMainProcess();
116 AssertIsOnBackgroundThread();
117 MOZ_ASSERT(aManager
);
120 ParentToChildServiceWorkerFetchEventOpArgs
copyArgs(aArgs
.common(), Nothing(),
121 Nothing(), Nothing());
122 if (aArgs
.preloadResponse().isSome()) {
123 // Convert the preload response to ParentToChildInternalResponse.
124 copyArgs
.preloadResponse() = Some(ToParentToChild(
125 aArgs
.preloadResponse().ref(), WrapNotNull(aManager
->Manager())));
128 if (aArgs
.preloadResponseTiming().isSome()) {
129 copyArgs
.preloadResponseTiming() = aArgs
.preloadResponseTiming();
132 if (aArgs
.preloadResponseEndArgs().isSome()) {
133 copyArgs
.preloadResponseEndArgs() = aArgs
.preloadResponseEndArgs();
136 RefPtr
<FetchEventOpProxyParent
> actor
=
137 new FetchEventOpProxyParent(std::move(aReal
), std::move(aPromise
));
139 // As long as the fetch event was pending, the FetchEventOpParent was
140 // responsible for keeping the preload response, if it already arrived. Once
141 // the fetch event starts it gives up the preload response (if any) and we
142 // need to add it to the arguments. Note that we have to make sure that the
143 // arguments don't contain the preload response already, otherwise we'll end
144 // up overwriting it with a Nothing.
145 auto [preloadResponse
, preloadResponseEndArgs
] =
146 actor
->mReal
->OnStart(WrapNotNull(actor
));
147 if (copyArgs
.preloadResponse().isNothing() && preloadResponse
.isSome()) {
148 copyArgs
.preloadResponse() = Some(ToParentToChild(
149 preloadResponse
.ref(), WrapNotNull(aManager
->Manager())));
151 if (copyArgs
.preloadResponseEndArgs().isNothing() &&
152 preloadResponseEndArgs
.isSome()) {
153 copyArgs
.preloadResponseEndArgs() = preloadResponseEndArgs
;
156 IPCInternalRequest
& copyRequest
= copyArgs
.common().internalRequest();
159 copyRequest
.body() = Some(ParentToChildStream());
161 RefPtr
<RemoteLazyInputStream
> stream
=
162 RemoteLazyInputStream::WrapStream(aBodyStream
);
163 MOZ_DIAGNOSTIC_ASSERT(stream
);
165 copyRequest
.body().ref().get_ParentToChildStream() = stream
;
168 Unused
<< aManager
->SendPFetchEventOpProxyConstructor(actor
, copyArgs
);
171 FetchEventOpProxyParent::~FetchEventOpProxyParent() {
172 AssertIsOnBackgroundThread();
175 FetchEventOpProxyParent::FetchEventOpProxyParent(
176 RefPtr
<FetchEventOpParent
>&& aReal
,
177 RefPtr
<ServiceWorkerFetchEventOpPromise::Private
>&& aPromise
)
178 : mReal(std::move(aReal
)), mLifetimePromise(std::move(aPromise
)) {}
180 mozilla::ipc::IPCResult
FetchEventOpProxyParent::RecvAsyncLog(
181 const nsCString
& aScriptSpec
, const uint32_t& aLineNumber
,
182 const uint32_t& aColumnNumber
, const nsCString
& aMessageName
,
183 nsTArray
<nsString
>&& aParams
) {
184 AssertIsOnBackgroundThread();
187 Unused
<< mReal
->SendAsyncLog(aScriptSpec
, aLineNumber
, aColumnNumber
,
188 aMessageName
, aParams
);
193 mozilla::ipc::IPCResult
FetchEventOpProxyParent::RecvRespondWith(
194 const ChildToParentFetchEventRespondWithResult
& aResult
) {
195 AssertIsOnBackgroundThread();
198 auto manager
= WrapNotNull(mReal
->Manager());
199 auto backgroundParent
= WrapNotNull(manager
->Manager());
200 Unused
<< mReal
->SendRespondWith(ToParentToParent(aResult
, backgroundParent
));
204 mozilla::ipc::IPCResult
FetchEventOpProxyParent::Recv__delete__(
205 const ServiceWorkerFetchEventOpResult
& aResult
) {
206 AssertIsOnBackgroundThread();
207 MOZ_ASSERT(mLifetimePromise
);
210 if (mLifetimePromise
) {
211 mLifetimePromise
->Resolve(aResult
, __func__
);
212 mLifetimePromise
= nullptr;
219 void FetchEventOpProxyParent::ActorDestroy(ActorDestroyReason
) {
220 AssertIsOnBackgroundThread();
221 if (mLifetimePromise
) {
222 mLifetimePromise
->Reject(NS_ERROR_DOM_ABORT_ERR
, __func__
);
223 mLifetimePromise
= nullptr;
229 } // namespace mozilla