LCOV - code coverage report
Current view: top level - dom/ipc - StructuredCloneData.h (source / functions) Hit Total Coverage
Test: output.info Lines: 31 50 62.0 %
Date: 2017-07-14 16:53:18 Functions: 16 22 72.7 %
Legend: Lines: hit not hit

          Line data    Source code
       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             : #ifndef mozilla_dom_ipc_StructuredCloneData_h
       8             : #define mozilla_dom_ipc_StructuredCloneData_h
       9             : 
      10             : #include <algorithm>
      11             : #include "mozilla/RefPtr.h"
      12             : #include "mozilla/dom/StructuredCloneHolder.h"
      13             : #include "nsISupportsImpl.h"
      14             : #include "nsIInputStream.h"
      15             : 
      16             : namespace IPC {
      17             : class Message;
      18             : }
      19             : class PickleIterator;
      20             : 
      21             : namespace mozilla {
      22             : namespace ipc {
      23             : 
      24             : class AutoIPCStream;
      25             : class PBackgroundChild;
      26             : class PBackgroundParent;
      27             : 
      28             : } // namespace ipc
      29             : 
      30             : namespace dom {
      31             : 
      32             : class nsIContentChild;
      33             : class nsIContentParent;
      34             : 
      35             : namespace ipc {
      36             : 
      37             : /**
      38             :  * Wraps the non-reference-counted JSStructuredCloneData class to have a
      39             :  * reference count so that multiple StructuredCloneData instances can reference
      40             :  * a single underlying serialized representation.
      41             :  *
      42             :  * As used by StructuredCloneData, it is an invariant that our
      43             :  * JSStructuredCloneData owns its buffers.  (For the non-owning case,
      44             :  * StructuredCloneData uses mExternalData which holds a BufferList::Borrow()ed
      45             :  * read-only view of the data.)
      46             :  */
      47             : class SharedJSAllocatedData final
      48             : {
      49             : public:
      50          46 :   explicit SharedJSAllocatedData(JSStructuredCloneData&& aData)
      51          46 :     : mData(Move(aData))
      52          46 :   { }
      53             : 
      54             :   static already_AddRefed<SharedJSAllocatedData>
      55           0 :   CreateFromExternalData(const char* aData, size_t aDataLength)
      56             :   {
      57           0 :     JSStructuredCloneData buf;
      58           0 :     buf.WriteBytes(aData, aDataLength);
      59             :     RefPtr<SharedJSAllocatedData> sharedData =
      60           0 :       new SharedJSAllocatedData(Move(buf));
      61           0 :     return sharedData.forget();
      62             :   }
      63             : 
      64             :   static already_AddRefed<SharedJSAllocatedData>
      65           0 :   CreateFromExternalData(const JSStructuredCloneData& aData)
      66             :   {
      67           0 :     JSStructuredCloneData buf;
      68           0 :     auto iter = aData.Iter();
      69           0 :     while (!iter.Done()) {
      70           0 :       buf.WriteBytes(iter.Data(), iter.RemainingInSegment());
      71           0 :       iter.Advance(aData, iter.RemainingInSegment());
      72             :     }
      73             :     RefPtr<SharedJSAllocatedData> sharedData =
      74           0 :       new SharedJSAllocatedData(Move(buf));
      75           0 :     return sharedData.forget();
      76             :   }
      77             : 
      78         150 :   NS_INLINE_DECL_REFCOUNTING(SharedJSAllocatedData)
      79             : 
      80         125 :   JSStructuredCloneData& Data() { return mData; }
      81          46 :   size_t DataLength() const { return mData.Size(); }
      82             : 
      83             : private:
      84          46 :   ~SharedJSAllocatedData() { }
      85             : 
      86             :   JSStructuredCloneData mData;
      87             : };
      88             : 
      89             : /**
      90             :  * IPC-aware StructuredCloneHolder subclass that serves as both a helper class
      91             :  * for dealing with message data (blobs, transferables) and also an IPDL
      92             :  * data-type in cases where message data is not needed.  If your use-case does
      93             :  * not (potentially) involve IPC, then you should use StructuredCloneHolder or
      94             :  * one of its other subclasses instead.
      95             :  *
      96             :  * ## Usage ##
      97             :  *
      98             :  * The general recipe for using this class is:
      99             :  * - In your IPDL definition, use the ClonedMessageData type whenever you want
     100             :  *   to send a structured clone that may include blobs or transferables such as
     101             :  *   message ports.
     102             :  * - To send the data, instantiate a StructuredCloneData instance and Write()
     103             :  *   into it like a normal structure clone.  When you are ready to send the
     104             :  *   ClonedMessageData-bearing IPC message, use the appropriate
     105             :  *   BuildClonedMessageDataFor{Parent,Child,BackgroundParent,BackgroundChild}
     106             :  *   method to populate the ClonedMessageData and then send it before your
     107             :  *   StructuredCloneData instance is destroyed.  (Buffer borrowing is used
     108             :  *   under-the-hood to avoid duplicating the serialized data, requiring this.)
     109             :  * - To receive the data, instantiate a StructuredCloneData and use the
     110             :  *   appropriate {Borrow,Copy,Steal}FromClonedMessageDataFor{Parent,Child,
     111             :  *   BackgroundParent,BackgroundChild} method.  See the memory management
     112             :  *   section for more info.
     113             :  *
     114             :  * Variations:
     115             :  * - If transferables are not allowed (ex: BroadcastChannel), then use the
     116             :  *   StructuredCloneDataNoTransfers subclass instead of StructuredCloneData.
     117             :  *
     118             :  * ## Memory Management ##
     119             :  *
     120             :  * Serialized structured clone representations can be quite large.  So it's best
     121             :  * to avoid wasteful duplication.  When Write()ing into the StructuredCloneData,
     122             :  * you don't need to worry about this[1], but when you already have serialized
     123             :  * structured clone data you plan to Read(), you do need to.  Similarly, if
     124             :  * you're using StructuredCloneData as an IPDL type, it efficiently unmarshals.
     125             :  *
     126             :  * The from-ClonedMessageData memory management strategies available are:
     127             :  * - Borrow: Create a JSStructuredCloneData that holds a non-owning, read-only
     128             :  *   BufferList::Borrow()ed copy of the source.  Your StructuredCloneData needs
     129             :  *   to be destroyed before the source is.  Commonly used when the
     130             :  *   StructuredCloneData instance is stack-allocated (and Read() is used before
     131             :  *   the function returns).
     132             :  * - Copy: Makes a reference-counted copy of the source JSStructuredCloneData,
     133             :  *   making it safe for the StructuredCloneData to outlive the source data.
     134             :  * - Steal: Steal the buffers from the underlying JSStructuredCloneData so that
     135             :  *   it's safe for the StructuredCloneData to outlive the source data.  This is
     136             :  *   safe to use with IPC-provided ClonedMessageData instances because
     137             :  *   JSStructuredCloneData's IPC ParamTraits::Read method uses ExtractBuffers,
     138             :  *   returning a fatal false if unable to extract.  (And
     139             :  *   SerializedStructuredCloneBuffer wraps/defers to it.)  But if it's possible
     140             :  *   the ClonedMessageData came from a different source that might have borrowed
     141             :  *   the buffers itself, then things will crash.  That would be a pretty crazy
     142             :  *   implementation; if you see one, change it to use SharedJSAllocatedData.
     143             :  *
     144             :  * 1: Specifically, in the Write() case an owning SharedJSAllocatedData is
     145             :  *    created efficiently (by stealing from StructuredCloneHolder).  The
     146             :  *    BuildClonedMessageDataFor* method can be called at any time and it will
     147             :  *    borrow the underlying memory.  While it would be even better if
     148             :  *    SerializedStructuredCloneBuffer could hold a SharedJSAllocatedData ref,
     149             :  *    there's no reason you can't wait to BuildClonedMessageDataFor* until you
     150             :  *    need to make the IPC Send* call.
     151             :  */
     152             : class StructuredCloneData : public StructuredCloneHolder
     153             : {
     154             : public:
     155             :   StructuredCloneData();
     156             : 
     157             :   StructuredCloneData(const StructuredCloneData&) = delete;
     158             : 
     159             :   StructuredCloneData(StructuredCloneData&& aOther);
     160             : 
     161             :   ~StructuredCloneData();
     162             : 
     163             :   StructuredCloneData&
     164             :   operator=(const StructuredCloneData& aOther) = delete;
     165             : 
     166             :   StructuredCloneData&
     167             :   operator=(StructuredCloneData&& aOther);
     168             : 
     169           6 :   const nsTArray<RefPtr<BlobImpl>>& BlobImpls() const
     170             :   {
     171           6 :     return mBlobImplArray;
     172             :   }
     173             : 
     174          56 :   nsTArray<RefPtr<BlobImpl>>& BlobImpls()
     175             :   {
     176          56 :     return mBlobImplArray;
     177             :   }
     178             : 
     179           6 :   const nsTArray<nsCOMPtr<nsIInputStream>>& InputStreams() const
     180             :   {
     181           6 :     return mInputStreamArray;
     182             :   }
     183             : 
     184          56 :   nsTArray<nsCOMPtr<nsIInputStream>>& InputStreams()
     185             :   {
     186          56 :     return mInputStreamArray;
     187             :   }
     188             : 
     189             :   bool Copy(const StructuredCloneData& aData);
     190             : 
     191             :   void Read(JSContext* aCx,
     192             :             JS::MutableHandle<JS::Value> aValue,
     193             :             ErrorResult &aRv);
     194             : 
     195             :   void Write(JSContext* aCx,
     196             :              JS::Handle<JS::Value> aValue,
     197             :              ErrorResult &aRv);
     198             : 
     199             :   void Write(JSContext* aCx,
     200             :              JS::Handle<JS::Value> aValue,
     201             :              JS::Handle<JS::Value> aTransfers,
     202             :              ErrorResult &aRv);
     203             : 
     204             :   // Actor-varying methods to convert the structured clone stored in this holder
     205             :   // by a previous call to Write() into ClonedMessageData IPC representation.
     206             :   // (Blobs are represented in IPC by IPCBlob actors, so we need the parent to
     207             :   // be able to create them.)
     208             :   bool BuildClonedMessageDataForParent(nsIContentParent* aParent,
     209             :                                        ClonedMessageData& aClonedData);
     210             :   bool BuildClonedMessageDataForChild(nsIContentChild* aChild,
     211             :                                       ClonedMessageData& aClonedData);
     212             :   bool BuildClonedMessageDataForBackgroundParent(mozilla::ipc::PBackgroundParent* aParent,
     213             :                                                  ClonedMessageData& aClonedData);
     214             :   bool BuildClonedMessageDataForBackgroundChild(mozilla::ipc::PBackgroundChild* aChild,
     215             :                                                 ClonedMessageData& aClonedData);
     216             : 
     217             :   // Actor-varying and memory-management-strategy-varying methods to initialize
     218             :   // this holder from a ClonedMessageData representation.
     219             :   void BorrowFromClonedMessageDataForParent(const ClonedMessageData& aClonedData);
     220             :   void BorrowFromClonedMessageDataForChild(const ClonedMessageData& aClonedData);
     221             :   void BorrowFromClonedMessageDataForBackgroundParent(const ClonedMessageData& aClonedData);
     222             :   void BorrowFromClonedMessageDataForBackgroundChild(const ClonedMessageData& aClonedData);
     223             : 
     224             :   void CopyFromClonedMessageDataForParent(const ClonedMessageData& aClonedData);
     225             :   void CopyFromClonedMessageDataForChild(const ClonedMessageData& aClonedData);
     226             :   void CopyFromClonedMessageDataForBackgroundParent(const ClonedMessageData& aClonedData);
     227             :   void CopyFromClonedMessageDataForBackgroundChild(const ClonedMessageData& aClonedData);
     228             : 
     229             :   // The steal variants of course take a non-const ClonedMessageData.
     230             :   void StealFromClonedMessageDataForParent(ClonedMessageData& aClonedData);
     231             :   void StealFromClonedMessageDataForChild(ClonedMessageData& aClonedData);
     232             :   void StealFromClonedMessageDataForBackgroundParent(ClonedMessageData& aClonedData);
     233             :   void StealFromClonedMessageDataForBackgroundChild(ClonedMessageData& aClonedData);
     234             : 
     235             : 
     236             :   // Initialize this instance, borrowing the contents of the given
     237             :   // JSStructuredCloneData.  You are responsible for ensuring that this
     238             :   // StructuredCloneData instance is destroyed before aData is destroyed.
     239          42 :   bool UseExternalData(const JSStructuredCloneData& aData)
     240             :   {
     241          42 :     auto iter = aData.Iter();
     242          42 :     bool success = false;
     243             :     mExternalData =
     244          42 :       aData.Borrow<js::SystemAllocPolicy>(iter, aData.Size(), &success);
     245          42 :     mInitialized = true;
     246          42 :     return success;
     247             :   }
     248             : 
     249             :   // Initialize this instance by copying the given data that probably came from
     250             :   // nsStructuredClone doing a base64 decode.  Don't use this.
     251             :   bool CopyExternalData(const char* aData, size_t aDataLength);
     252             :   // Initialize this instance by copying the contents of an existing
     253             :   // JSStructuredCloneData.  Use when this StructuredCloneData instance may
     254             :   // outlive aData.
     255             :   bool CopyExternalData(const JSStructuredCloneData& aData);
     256             : 
     257             :   // Initialize this instance by stealing the contents of aData via Move
     258             :   // constructor, clearing the original aData as a side-effect.  This is only
     259             :   // safe if aData owns the underlying buffers.  This is the case for instances
     260             :   // provided by IPC to Recv calls.
     261             :   bool StealExternalData(JSStructuredCloneData& aData);
     262             : 
     263         175 :   JSStructuredCloneData& Data()
     264             :   {
     265         175 :     return mSharedData ? mSharedData->Data() : mExternalData;
     266             :   }
     267             : 
     268           2 :   const JSStructuredCloneData& Data() const
     269             :   {
     270           2 :     return mSharedData ? mSharedData->Data() : mExternalData;
     271             :   }
     272             : 
     273          94 :   size_t DataLength() const
     274             :   {
     275          94 :     return mSharedData ? mSharedData->DataLength() : mExternalData.Size();
     276             :   }
     277             : 
     278          12 :   SharedJSAllocatedData* SharedData() const
     279             :   {
     280          12 :     return mSharedData;
     281             :   }
     282             : 
     283          86 :   bool SupportsTransferring()
     284             :   {
     285          86 :     return mSupportsTransferring;
     286             :   }
     287             : 
     288           0 :   FallibleTArray<mozilla::ipc::AutoIPCStream>& IPCStreams()
     289             :   {
     290           0 :     return mIPCStreams;
     291             :   }
     292             : 
     293             :   // For IPC serialization
     294             :   void WriteIPCParams(IPC::Message* aMessage) const;
     295             :   bool ReadIPCParams(const IPC::Message* aMessage, PickleIterator* aIter);
     296             : 
     297             : protected:
     298             :   explicit StructuredCloneData(TransferringSupport aSupportsTransferring);
     299             : 
     300             : private:
     301             :   JSStructuredCloneData mExternalData;
     302             :   RefPtr<SharedJSAllocatedData> mSharedData;
     303             : 
     304             :   // This array is needed because AutoIPCStream DTOR must be executed after the
     305             :   // sending of the data via IPC. This will be fixed by bug 1353475.
     306             :   FallibleTArray<mozilla::ipc::AutoIPCStream> mIPCStreams;
     307             :   bool mInitialized;
     308             : };
     309             : 
     310             : /**
     311             :  * For use when transferring should not be supported.
     312             :  */
     313           0 : class StructuredCloneDataNoTransfers : public StructuredCloneData
     314             : {
     315             : public:
     316           0 :   StructuredCloneDataNoTransfers()
     317           0 :     : StructuredCloneData(StructuredCloneHolder::TransferringNotSupported)
     318           0 :   {}
     319             : };
     320             : 
     321             : } // namespace ipc
     322             : } // namespace dom
     323             : } // namespace mozilla
     324             : 
     325             : #endif // mozilla_dom_ipc_StructuredCloneData_h

Generated by: LCOV version 1.13