tor-browser

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

CacheStreamControlChild.cpp (5161B)


      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 "CacheStreamControlChild.h"
      8 
      9 #include "mozilla/dom/cache/ActorUtils.h"
     10 #include "mozilla/dom/cache/CacheTypes.h"
     11 #include "mozilla/dom/cache/CacheWorkerRef.h"
     12 #include "mozilla/ipc/IPCStreamUtils.h"
     13 #include "mozilla/ipc/PBackgroundChild.h"
     14 #include "nsISupportsImpl.h"
     15 
     16 namespace mozilla::dom::cache {
     17 
     18 using mozilla::ipc::FileDescriptor;
     19 
     20 // declared in ActorUtils.h
     21 already_AddRefed<PCacheStreamControlChild> AllocPCacheStreamControlChild(
     22    ActorChild* aParentActor) {
     23  return MakeAndAddRef<CacheStreamControlChild>(aParentActor);
     24 }
     25 
     26 CacheStreamControlChild::CacheStreamControlChild(ActorChild* aParentActor)
     27    : mParentActor(aParentActor),
     28      mDestroyStarted(false),
     29      mDestroyDelayed(false) {
     30  MOZ_COUNT_CTOR(cache::CacheStreamControlChild);
     31 }
     32 
     33 CacheStreamControlChild::~CacheStreamControlChild() {
     34  NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
     35  MOZ_COUNT_DTOR(cache::CacheStreamControlChild);
     36 }
     37 
     38 void CacheStreamControlChild::StartDestroy() {
     39  NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
     40  // This can get called twice under some circumstances.  For example, if the
     41  // actor is added to a CacheWorkerRef that has already been notified and
     42  // the Cache actor has no mListener.
     43  if (mDestroyStarted) {
     44    return;
     45  }
     46  mDestroyStarted = true;
     47 
     48  // If any of the streams have started to be read, then wait for them to close
     49  // naturally.
     50  if (HasEverBeenRead()) {
     51    // Note that we are delaying so that we can re-check for active streams
     52    // in NoteClosedAfterForget().
     53    mDestroyDelayed = true;
     54    return;
     55  }
     56 
     57  // Otherwise, if the streams have not been touched then just pre-emptively
     58  // close them now.  This handles the case where someone retrieves a Response
     59  // from the Cache, but never accesses the body.  We should not keep the
     60  // Worker alive until that Response is GC'd just because of its ignored
     61  // body stream.
     62 
     63  // Begin shutting down all streams.  This is the same as if the parent had
     64  // asked us to shutdown.  So simulate the CloseAll IPC message.
     65  RecvCloseAll();
     66 }
     67 
     68 void CacheStreamControlChild::SerializeControl(
     69    CacheReadStream* aReadStreamOut) {
     70  NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
     71  MOZ_DIAGNOSTIC_ASSERT(aReadStreamOut);
     72  aReadStreamOut->control() = this;
     73 }
     74 
     75 void CacheStreamControlChild::SerializeStream(CacheReadStream* aReadStreamOut,
     76                                              nsIInputStream* aStream) {
     77  NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
     78  MOZ_DIAGNOSTIC_ASSERT(aReadStreamOut);
     79  MOZ_ALWAYS_TRUE(mozilla::ipc::SerializeIPCStream(
     80      do_AddRef(aStream), aReadStreamOut->stream(), /* aAllowLazy */ false));
     81 }
     82 
     83 void CacheStreamControlChild::OpenStream(const nsID& aId,
     84                                         InputStreamResolver&& aResolver) {
     85  NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
     86 
     87  if (mDestroyStarted) {
     88    aResolver(nullptr);
     89    return;
     90  }
     91 
     92  // If we are on a worker, then we need to hold it alive until the async
     93  // IPC operation below completes.  While the IPC layer will trigger a
     94  // rejection here in many cases, we must handle the case where the
     95  // MozPromise resolve runnable is already in the event queue when the
     96  // worker wants to shut down.
     97  const SafeRefPtr<CacheWorkerRef> holder = GetWorkerRefPtr().clonePtr();
     98 
     99  SendOpenStream(aId)->Then(
    100      GetCurrentSerialEventTarget(), __func__,
    101      [aResolver,
    102       holder = holder.clonePtr()](const Maybe<IPCStream>& aOptionalStream) {
    103        nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(aOptionalStream);
    104        aResolver(std::move(stream));
    105      },
    106      [aResolver, holder = holder.clonePtr()](ResponseRejectReason&& aReason) {
    107        aResolver(nullptr);
    108      });
    109 }
    110 
    111 void CacheStreamControlChild::NoteClosedAfterForget(const nsID& aId) {
    112  NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
    113 
    114  QM_WARNONLY_TRY(OkIf(SendNoteClosed(aId)));
    115 
    116  // A stream has closed.  If we delayed StartDestry() due to this stream
    117  // being read, then we should check to see if any of the remaining streams
    118  // are active.  If none of our other streams have been read, then we can
    119  // proceed with the shutdown now.
    120  if (mDestroyDelayed && !HasEverBeenRead()) {
    121    mDestroyDelayed = false;
    122    RecvCloseAll();
    123  }
    124 }
    125 
    126 #ifdef DEBUG
    127 void CacheStreamControlChild::AssertOwningThread() {
    128  NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
    129 }
    130 #endif
    131 
    132 void CacheStreamControlChild::ActorDestroy(ActorDestroyReason aReason) {
    133  NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
    134  CloseAllReadStreamsWithoutReporting();
    135 
    136  if (mParentActor) {
    137    mParentActor->NoteDeletedActor();
    138  }
    139 
    140  RemoveWorkerRef();
    141 }
    142 
    143 mozilla::ipc::IPCResult CacheStreamControlChild::RecvCloseAll() {
    144  NS_ASSERT_OWNINGTHREAD(CacheStreamControlChild);
    145  CloseAllReadStreams();
    146  return IPC_OK();
    147 }
    148 
    149 }  // namespace mozilla::dom::cache