tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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