FetchEventOpProxyParent.cpp (7782B)
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/. */ 6 7 #include "FetchEventOpProxyParent.h" 8 9 #include <utility> 10 11 #include "mozilla/Assertions.h" 12 #include "mozilla/RemoteLazyInputStreamStorage.h" 13 #include "mozilla/Try.h" 14 #include "mozilla/dom/FetchEventOpParent.h" 15 #include "mozilla/dom/FetchTypes.h" 16 #include "mozilla/dom/InternalResponse.h" 17 #include "mozilla/dom/PRemoteWorkerControllerParent.h" 18 #include "mozilla/dom/PRemoteWorkerParent.h" 19 #include "mozilla/dom/PRemoteWorkerServiceParent.h" 20 #include "mozilla/dom/ServiceWorkerOpArgs.h" 21 #include "mozilla/ipc/BackgroundParent.h" 22 #include "mozilla/ipc/IPCStreamUtils.h" 23 #include "mozilla/ipc/PBackgroundParent.h" 24 #include "nsCOMPtr.h" 25 #include "nsIInputStream.h" 26 27 namespace mozilla { 28 29 using namespace ipc; 30 31 namespace dom { 32 33 namespace { 34 35 nsresult MaybeDeserializeAndWrapForMainThread( 36 const Maybe<ChildToParentStream>& aSource, int64_t aBodyStreamSize, 37 Maybe<ParentToParentStream>& aSink, PBackgroundParent* aManager) { 38 if (aSource.isNothing()) { 39 return NS_OK; 40 } 41 42 nsCOMPtr<nsIInputStream> deserialized = 43 DeserializeIPCStream(aSource->stream()); 44 45 aSink = Some(ParentToParentStream()); 46 auto& uuid = aSink->uuid(); 47 48 MOZ_TRY(nsID::GenerateUUIDInPlace(uuid)); 49 50 auto storageOrErr = RemoteLazyInputStreamStorage::Get(); 51 52 if (NS_WARN_IF(storageOrErr.isErr())) { 53 return storageOrErr.unwrapErr(); 54 } 55 56 auto storage = storageOrErr.unwrap(); 57 storage->AddStream(deserialized, uuid); 58 return NS_OK; 59 } 60 61 ParentToParentInternalResponse ToParentToParent( 62 const ChildToParentInternalResponse& aResponse, 63 NotNull<PBackgroundParent*> aBackgroundParent) { 64 ParentToParentInternalResponse parentToParentResponse( 65 aResponse.metadata(), Nothing(), aResponse.bodySize(), Nothing()); 66 67 MOZ_ALWAYS_SUCCEEDS(MaybeDeserializeAndWrapForMainThread( 68 aResponse.body(), aResponse.bodySize(), parentToParentResponse.body(), 69 aBackgroundParent)); 70 MOZ_ALWAYS_SUCCEEDS(MaybeDeserializeAndWrapForMainThread( 71 aResponse.alternativeBody(), InternalResponse::UNKNOWN_BODY_SIZE, 72 parentToParentResponse.alternativeBody(), aBackgroundParent)); 73 74 return parentToParentResponse; 75 } 76 77 ParentToParentSynthesizeResponseArgs ToParentToParent( 78 const ChildToParentSynthesizeResponseArgs& aArgs, 79 NotNull<PBackgroundParent*> aBackgroundParent) { 80 return ParentToParentSynthesizeResponseArgs( 81 ToParentToParent(aArgs.internalResponse(), aBackgroundParent), 82 aArgs.closure(), aArgs.timeStamps()); 83 } 84 85 ParentToParentFetchEventRespondWithResult ToParentToParent( 86 const ChildToParentFetchEventRespondWithResult& aResult, 87 NotNull<PBackgroundParent*> aBackgroundParent) { 88 switch (aResult.type()) { 89 case ChildToParentFetchEventRespondWithResult:: 90 TChildToParentSynthesizeResponseArgs: 91 return ToParentToParent(aResult.get_ChildToParentSynthesizeResponseArgs(), 92 aBackgroundParent); 93 94 case ChildToParentFetchEventRespondWithResult::TResetInterceptionArgs: 95 return aResult.get_ResetInterceptionArgs(); 96 97 case ChildToParentFetchEventRespondWithResult::TCancelInterceptionArgs: 98 return aResult.get_CancelInterceptionArgs(); 99 100 default: 101 MOZ_CRASH("Invalid ParentToParentFetchEventRespondWithResult"); 102 } 103 } 104 105 } // anonymous namespace 106 107 /* static */ void FetchEventOpProxyParent::Create( 108 PRemoteWorkerParent* aManager, 109 RefPtr<ServiceWorkerFetchEventOpPromise::Private>&& aPromise, 110 const ParentToParentServiceWorkerFetchEventOpArgs& aArgs, 111 RefPtr<FetchEventOpParent> aReal, nsCOMPtr<nsIInputStream> aBodyStream) { 112 AssertIsInMainProcess(); 113 AssertIsOnBackgroundThread(); 114 MOZ_ASSERT(aManager); 115 MOZ_ASSERT(aReal); 116 117 ParentToChildServiceWorkerFetchEventOpArgs copyArgs(aArgs.common(), Nothing(), 118 Nothing(), Nothing()); 119 if (aArgs.preloadResponse().isSome()) { 120 // Convert the preload response to ParentToChildInternalResponse. 121 copyArgs.preloadResponse() = 122 Some(ToParentToChild(aArgs.preloadResponse().ref())); 123 } 124 125 if (aArgs.preloadResponseTiming().isSome()) { 126 copyArgs.preloadResponseTiming() = aArgs.preloadResponseTiming(); 127 } 128 129 if (aArgs.preloadResponseEndArgs().isSome()) { 130 copyArgs.preloadResponseEndArgs() = aArgs.preloadResponseEndArgs(); 131 } 132 133 RefPtr<FetchEventOpProxyParent> actor = 134 new FetchEventOpProxyParent(std::move(aReal), std::move(aPromise)); 135 136 // As long as the fetch event was pending, the FetchEventOpParent was 137 // responsible for keeping the preload response, if it already arrived. Once 138 // the fetch event starts it gives up the preload response (if any) and we 139 // need to add it to the arguments. Note that we have to make sure that the 140 // arguments don't contain the preload response already, otherwise we'll end 141 // up overwriting it with a Nothing. 142 auto [preloadResponse, preloadResponseEndArgs] = 143 actor->mReal->OnStart(WrapNotNull(actor)); 144 if (copyArgs.preloadResponse().isNothing() && preloadResponse.isSome()) { 145 copyArgs.preloadResponse() = Some(ToParentToChild(preloadResponse.ref())); 146 } 147 if (copyArgs.preloadResponseEndArgs().isNothing() && 148 preloadResponseEndArgs.isSome()) { 149 copyArgs.preloadResponseEndArgs() = preloadResponseEndArgs; 150 } 151 152 IPCInternalRequest& copyRequest = copyArgs.common().internalRequest(); 153 154 if (aBodyStream) { 155 copyRequest.body() = Some(ParentToChildStream()); 156 157 RefPtr<RemoteLazyInputStream> stream = 158 RemoteLazyInputStream::WrapStream(aBodyStream); 159 MOZ_DIAGNOSTIC_ASSERT(stream); 160 161 copyRequest.body().ref().get_ParentToChildStream() = stream; 162 } 163 164 (void)aManager->SendPFetchEventOpProxyConstructor(actor, copyArgs); 165 } 166 167 FetchEventOpProxyParent::~FetchEventOpProxyParent() { 168 AssertIsOnBackgroundThread(); 169 } 170 171 FetchEventOpProxyParent::FetchEventOpProxyParent( 172 RefPtr<FetchEventOpParent>&& aReal, 173 RefPtr<ServiceWorkerFetchEventOpPromise::Private>&& aPromise) 174 : mReal(std::move(aReal)), mLifetimePromise(std::move(aPromise)) {} 175 176 mozilla::ipc::IPCResult FetchEventOpProxyParent::RecvAsyncLog( 177 const nsCString& aScriptSpec, const uint32_t& aLineNumber, 178 const uint32_t& aColumnNumber, const nsCString& aMessageName, 179 nsTArray<nsString>&& aParams) { 180 AssertIsOnBackgroundThread(); 181 MOZ_ASSERT(mReal); 182 183 (void)mReal->SendAsyncLog(aScriptSpec, aLineNumber, aColumnNumber, 184 aMessageName, aParams); 185 186 return IPC_OK(); 187 } 188 189 mozilla::ipc::IPCResult FetchEventOpProxyParent::RecvRespondWith( 190 const ChildToParentFetchEventRespondWithResult& aResult) { 191 AssertIsOnBackgroundThread(); 192 MOZ_ASSERT(mReal); 193 194 auto manager = WrapNotNull(mReal->Manager()); 195 auto backgroundParent = WrapNotNull(manager->Manager()); 196 (void)mReal->SendRespondWith(ToParentToParent(aResult, backgroundParent)); 197 return IPC_OK(); 198 } 199 200 mozilla::ipc::IPCResult FetchEventOpProxyParent::Recv__delete__( 201 const ServiceWorkerFetchEventOpResult& aResult) { 202 AssertIsOnBackgroundThread(); 203 MOZ_ASSERT(mLifetimePromise); 204 MOZ_ASSERT(mReal); 205 mReal->OnFinish(); 206 if (mLifetimePromise) { 207 mLifetimePromise->Resolve(aResult, __func__); 208 mLifetimePromise = nullptr; 209 mReal = nullptr; 210 } 211 212 return IPC_OK(); 213 } 214 215 void FetchEventOpProxyParent::ActorDestroy(ActorDestroyReason) { 216 AssertIsOnBackgroundThread(); 217 if (mLifetimePromise) { 218 mLifetimePromise->Reject(NS_ERROR_DOM_ABORT_ERR, __func__); 219 mLifetimePromise = nullptr; 220 mReal = nullptr; 221 } 222 } 223 224 } // namespace dom 225 } // namespace mozilla