LCOV - code coverage report
Current view: top level - dom/ipc - StructuredCloneData.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 92 204 45.1 %
Date: 2017-07-14 16:53:18 Functions: 18 44 40.9 %
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             : #include "StructuredCloneData.h"
       8             : 
       9             : #include "nsIDOMDOMException.h"
      10             : #include "nsIMutable.h"
      11             : #include "nsIXPConnect.h"
      12             : 
      13             : #include "ipc/IPCMessageUtils.h"
      14             : #include "mozilla/dom/BindingUtils.h"
      15             : #include "mozilla/dom/BlobBinding.h"
      16             : #include "mozilla/dom/IPCBlobUtils.h"
      17             : #include "mozilla/dom/File.h"
      18             : #include "mozilla/ipc/IPCStreamUtils.h"
      19             : #include "nsContentUtils.h"
      20             : #include "nsJSEnvironment.h"
      21             : #include "MainThreadUtils.h"
      22             : #include "StructuredCloneTags.h"
      23             : #include "jsapi.h"
      24             : 
      25             : namespace mozilla {
      26             : namespace dom {
      27             : namespace ipc {
      28             : 
      29         101 : StructuredCloneData::StructuredCloneData()
      30         101 :   : StructuredCloneData(StructuredCloneHolder::TransferringSupported)
      31         101 : {}
      32             : 
      33           0 : StructuredCloneData::StructuredCloneData(StructuredCloneData&& aOther)
      34           0 :   : StructuredCloneData(StructuredCloneHolder::TransferringSupported)
      35             : {
      36           0 :   *this = Move(aOther);
      37           0 : }
      38             : 
      39         101 : StructuredCloneData::StructuredCloneData(TransferringSupport aSupportsTransferring)
      40             :   : StructuredCloneHolder(StructuredCloneHolder::CloningSupported,
      41             :                           aSupportsTransferring,
      42             :                           StructuredCloneHolder::StructuredCloneScope::DifferentProcess)
      43         101 :   , mInitialized(false)
      44         101 : {}
      45             : 
      46         100 : StructuredCloneData::~StructuredCloneData()
      47         100 : {}
      48             : 
      49             : StructuredCloneData&
      50           0 : StructuredCloneData::operator=(StructuredCloneData&& aOther)
      51             : {
      52           0 :   mExternalData = Move(aOther.mExternalData);
      53           0 :   mSharedData = Move(aOther.mSharedData);
      54           0 :   mIPCStreams = Move(aOther.mIPCStreams);
      55           0 :   mInitialized = aOther.mInitialized;
      56             : 
      57           0 :   return *this;
      58             : }
      59             : 
      60             : bool
      61           7 : StructuredCloneData::Copy(const StructuredCloneData& aData)
      62             : {
      63           7 :   if (!aData.mInitialized) {
      64           1 :     return true;
      65             :   }
      66             : 
      67           6 :   if (aData.SharedData()) {
      68           6 :     mSharedData = aData.SharedData();
      69             :   } else {
      70             :     mSharedData =
      71           0 :       SharedJSAllocatedData::CreateFromExternalData(aData.Data());
      72           0 :     NS_ENSURE_TRUE(mSharedData, false);
      73             :   }
      74             : 
      75           6 :   if (mSupportsTransferring) {
      76           6 :     PortIdentifiers().AppendElements(aData.PortIdentifiers());
      77             :   }
      78             : 
      79           6 :   MOZ_ASSERT(BlobImpls().IsEmpty());
      80           6 :   BlobImpls().AppendElements(aData.BlobImpls());
      81             : 
      82           6 :   MOZ_ASSERT(GetSurfaces().IsEmpty());
      83           6 :   MOZ_ASSERT(WasmModules().IsEmpty());
      84             : 
      85           6 :   MOZ_ASSERT(InputStreams().IsEmpty());
      86           6 :   InputStreams().AppendElements(aData.InputStreams());
      87             : 
      88           6 :   mInitialized = true;
      89             : 
      90           6 :   return true;
      91             : }
      92             : 
      93             : void
      94          43 : StructuredCloneData::Read(JSContext* aCx,
      95             :                           JS::MutableHandle<JS::Value> aValue,
      96             :                           ErrorResult &aRv)
      97             : {
      98          43 :   MOZ_ASSERT(mInitialized);
      99             : 
     100          43 :   nsIGlobalObject *global = xpc::NativeGlobal(JS::CurrentGlobalOrNull(aCx));
     101          43 :   MOZ_ASSERT(global);
     102             : 
     103          43 :   ReadFromBuffer(global, aCx, Data(), aValue, aRv);
     104          43 : }
     105             : 
     106             : void
     107           2 : StructuredCloneData::Write(JSContext* aCx,
     108             :                            JS::Handle<JS::Value> aValue,
     109             :                            ErrorResult &aRv)
     110             : {
     111           2 :   Write(aCx, aValue, JS::UndefinedHandleValue, aRv);
     112           2 : }
     113             : 
     114             : void
     115          44 : StructuredCloneData::Write(JSContext* aCx,
     116             :                            JS::Handle<JS::Value> aValue,
     117             :                            JS::Handle<JS::Value> aTransfer,
     118             :                            ErrorResult &aRv)
     119             : {
     120          44 :   MOZ_ASSERT(!mInitialized);
     121             : 
     122          44 :   StructuredCloneHolder::Write(aCx, aValue, aTransfer,
     123          88 :                                JS::CloneDataPolicy().denySharedArrayBuffer(), aRv);
     124          44 :   if (NS_WARN_IF(aRv.Failed())) {
     125           0 :     return;
     126             :   }
     127             : 
     128          88 :   JSStructuredCloneData data;
     129          44 :   mBuffer->abandon();
     130          44 :   mBuffer->steal(&data);
     131          44 :   mBuffer = nullptr;
     132          88 :   mSharedData = new SharedJSAllocatedData(Move(data));
     133          44 :   mInitialized = true;
     134             : }
     135             : 
     136             : enum ActorFlavorEnum {
     137             :   Parent = 0,
     138             :   Child,
     139             : };
     140             : 
     141             : enum ManagerFlavorEnum {
     142             :   ContentProtocol = 0,
     143             :   BackgroundProtocol
     144             : };
     145             : 
     146             : template<typename M>
     147             : bool
     148          44 : BuildClonedMessageData(M* aManager, StructuredCloneData& aData,
     149             :                        ClonedMessageData& aClonedData)
     150             : {
     151          44 :   SerializedStructuredCloneBuffer& buffer = aClonedData.data();
     152          44 :   auto iter = aData.Data().Iter();
     153          44 :   size_t size = aData.Data().Size();
     154             :   bool success;
     155          44 :   buffer.data = aData.Data().Borrow<js::SystemAllocPolicy>(iter, size, &success);
     156          44 :   if (NS_WARN_IF(!success)) {
     157           0 :     return false;
     158             :   }
     159          44 :   if (aData.SupportsTransferring()) {
     160          44 :     aClonedData.identfiers().AppendElements(aData.PortIdentifiers());
     161             :   }
     162             : 
     163          44 :   const nsTArray<RefPtr<BlobImpl>>& blobImpls = aData.BlobImpls();
     164             : 
     165          44 :   if (!blobImpls.IsEmpty()) {
     166           0 :     if (NS_WARN_IF(!aClonedData.blobs().SetLength(blobImpls.Length(), fallible))) {
     167           0 :       return false;
     168             :     }
     169             : 
     170           0 :     for (uint32_t i = 0; i < blobImpls.Length(); ++i) {
     171           0 :       nsresult rv = IPCBlobUtils::Serialize(blobImpls[i], aManager,
     172           0 :                                             aClonedData.blobs()[i]);
     173           0 :       if (NS_WARN_IF(NS_FAILED(rv))) {
     174           0 :         return false;
     175             :       }
     176             :     }
     177             :   }
     178             : 
     179          44 :   const nsTArray<nsCOMPtr<nsIInputStream>>& inputStreams = aData.InputStreams();
     180          44 :   if (!inputStreams.IsEmpty()) {
     181           0 :     if (NS_WARN_IF(!aData.IPCStreams().SetCapacity(inputStreams.Length(),
     182             :                                                    fallible))) {
     183           0 :       return false;
     184             :     }
     185             : 
     186           0 :     InfallibleTArray<IPCStream>& streams = aClonedData.inputStreams();
     187           0 :     uint32_t length = inputStreams.Length();
     188           0 :     streams.SetCapacity(length);
     189           0 :     for (uint32_t i = 0; i < length; ++i) {
     190           0 :       AutoIPCStream* stream = aData.IPCStreams().AppendElement(fallible);
     191           0 :       if (NS_WARN_IF(!stream)) {
     192           0 :         return false;
     193             :       }
     194             : 
     195           0 :       if (!stream->Serialize(inputStreams[i], aManager)) {
     196           0 :         return false;
     197             :       }
     198           0 :       streams.AppendElement(stream->TakeValue());
     199             :     }
     200             :   }
     201             : 
     202          44 :   return true;
     203             : }
     204             : 
     205             : bool
     206          10 : StructuredCloneData::BuildClonedMessageDataForParent(
     207             :   nsIContentParent* aParent,
     208             :   ClonedMessageData& aClonedData)
     209             : {
     210          10 :   return BuildClonedMessageData(aParent, *this, aClonedData);
     211             : }
     212             : 
     213             : bool
     214          34 : StructuredCloneData::BuildClonedMessageDataForChild(
     215             :   nsIContentChild* aChild,
     216             :   ClonedMessageData& aClonedData)
     217             : {
     218          34 :   return BuildClonedMessageData(aChild, *this, aClonedData);
     219             : }
     220             : 
     221             : bool
     222           0 : StructuredCloneData::BuildClonedMessageDataForBackgroundParent(
     223             :   PBackgroundParent* aParent,
     224             :   ClonedMessageData& aClonedData)
     225             : {
     226           0 :   return BuildClonedMessageData(aParent, *this, aClonedData);
     227             : }
     228             : 
     229             : bool
     230           0 : StructuredCloneData::BuildClonedMessageDataForBackgroundChild(
     231             :   PBackgroundChild* aChild,
     232             :   ClonedMessageData& aClonedData)
     233             : {
     234           0 :   return BuildClonedMessageData(aChild, *this, aClonedData);
     235             : }
     236             : 
     237             : // See the StructuredCloneData class block comment for the meanings of each val.
     238             : enum MemoryFlavorEnum {
     239             :   BorrowMemory = 0,
     240             :   CopyMemory,
     241             :   StealMemory
     242             : };
     243             : 
     244             : template<MemoryFlavorEnum>
     245             : struct MemoryTraits
     246             : { };
     247             : 
     248             : template<>
     249             : struct MemoryTraits<BorrowMemory>
     250             : {
     251             :   typedef const mozilla::dom::ClonedMessageData ClonedMessageType;
     252             : 
     253          42 :   static void ProvideBuffer(const ClonedMessageData& aClonedData,
     254             :                             StructuredCloneData& aData)
     255             :   {
     256          42 :     const SerializedStructuredCloneBuffer& buffer = aClonedData.data();
     257          42 :     aData.UseExternalData(buffer.data);
     258          42 :   }
     259             : };
     260             : 
     261             : template<>
     262             : struct MemoryTraits<CopyMemory>
     263             : {
     264             :   typedef const mozilla::dom::ClonedMessageData ClonedMessageType;
     265             : 
     266           0 :   static void ProvideBuffer(const ClonedMessageData& aClonedData,
     267             :                             StructuredCloneData& aData)
     268             :   {
     269           0 :     const SerializedStructuredCloneBuffer& buffer = aClonedData.data();
     270           0 :     aData.CopyExternalData(buffer.data);
     271           0 :   }
     272             : };
     273             : 
     274             : template<>
     275             : struct MemoryTraits<StealMemory>
     276             : {
     277             :   // note: not const!
     278             :   typedef mozilla::dom::ClonedMessageData ClonedMessageType;
     279             : 
     280           0 :   static void ProvideBuffer(ClonedMessageData& aClonedData,
     281             :                             StructuredCloneData& aData)
     282             :   {
     283           0 :     SerializedStructuredCloneBuffer& buffer = aClonedData.data();
     284           0 :     aData.StealExternalData(buffer.data);
     285           0 :   }
     286             : };
     287             : 
     288             : // Note that there isn't actually a difference between Parent/BackgroundParent
     289             : // and Child/BackgroundChild in this implementation.  The calling methods,
     290             : // however, do maintain the distinction for code-reading purposes and are backed
     291             : // by assertions to enforce there is no misuse.
     292             : template<MemoryFlavorEnum MemoryFlavor, ActorFlavorEnum Flavor>
     293             : static void
     294          42 : UnpackClonedMessageData(typename MemoryTraits<MemoryFlavor>::ClonedMessageType& aClonedData,
     295             :                         StructuredCloneData& aData)
     296             : {
     297          42 :   const InfallibleTArray<MessagePortIdentifier>& identifiers = aClonedData.identfiers();
     298             : 
     299          42 :   MemoryTraits<MemoryFlavor>::ProvideBuffer(aClonedData, aData);
     300             : 
     301          42 :   if (aData.SupportsTransferring()) {
     302          42 :     aData.PortIdentifiers().AppendElements(identifiers);
     303             :   }
     304             : 
     305          42 :   const nsTArray<IPCBlob>& blobs = aClonedData.blobs();
     306          42 :   if (!blobs.IsEmpty()) {
     307           0 :     uint32_t length = blobs.Length();
     308           0 :     aData.BlobImpls().SetCapacity(length);
     309           0 :     for (uint32_t i = 0; i < length; ++i) {
     310           0 :       RefPtr<BlobImpl> blobImpl = IPCBlobUtils::Deserialize(blobs[i]);
     311           0 :       MOZ_ASSERT(blobImpl);
     312             : 
     313           0 :       aData.BlobImpls().AppendElement(blobImpl);
     314             :     }
     315             :   }
     316             : 
     317          42 :   const InfallibleTArray<IPCStream>& streams = aClonedData.inputStreams();
     318          42 :   if (!streams.IsEmpty()) {
     319           0 :     uint32_t length = streams.Length();
     320           0 :     aData.InputStreams().SetCapacity(length);
     321           0 :     for (uint32_t i = 0; i < length; ++i) {
     322           0 :       nsCOMPtr<nsIInputStream> stream = DeserializeIPCStream(streams[i]);
     323           0 :       aData.InputStreams().AppendElement(stream);
     324             :     }
     325             :   }
     326          42 : }
     327             : 
     328             : void
     329          32 : StructuredCloneData::BorrowFromClonedMessageDataForParent(const ClonedMessageData& aClonedData)
     330             : {
     331             :   // PContent parent is always main thread and actor constraints demand we're
     332             :   // likewise on that thread.
     333          32 :   MOZ_ASSERT(NS_IsMainThread());
     334          32 :   UnpackClonedMessageData<BorrowMemory, Parent>(aClonedData, *this);
     335          32 : }
     336             : 
     337             : void
     338          10 : StructuredCloneData::BorrowFromClonedMessageDataForChild(const ClonedMessageData& aClonedData)
     339             : {
     340             :   // PContent child is always main thread and actor constraints demand we're
     341             :   // likewise on that thread.
     342          10 :   MOZ_ASSERT(NS_IsMainThread());
     343          10 :   UnpackClonedMessageData<BorrowMemory, Child>(aClonedData, *this);
     344          10 : }
     345             : 
     346             : void
     347           0 : StructuredCloneData::BorrowFromClonedMessageDataForBackgroundParent(const ClonedMessageData& aClonedData)
     348             : {
     349           0 :   MOZ_ASSERT(IsOnBackgroundThread());
     350           0 :   UnpackClonedMessageData<BorrowMemory, Parent>(aClonedData, *this);
     351           0 : }
     352             : 
     353             : void
     354           0 : StructuredCloneData::BorrowFromClonedMessageDataForBackgroundChild(const ClonedMessageData& aClonedData)
     355             : {
     356             :   // No thread assertion; BackgroundChild can happen on any thread.
     357           0 :   UnpackClonedMessageData<BorrowMemory, Child>(aClonedData, *this);
     358           0 : }
     359             : 
     360             : void
     361           0 : StructuredCloneData::CopyFromClonedMessageDataForParent(const ClonedMessageData& aClonedData)
     362             : {
     363           0 :   MOZ_ASSERT(NS_IsMainThread());
     364           0 :   UnpackClonedMessageData<CopyMemory, Parent>(aClonedData, *this);
     365           0 : }
     366             : 
     367             : void
     368           0 : StructuredCloneData::CopyFromClonedMessageDataForChild(const ClonedMessageData& aClonedData)
     369             : {
     370           0 :   MOZ_ASSERT(NS_IsMainThread());
     371           0 :   UnpackClonedMessageData<CopyMemory, Child>(aClonedData, *this);
     372           0 : }
     373             : 
     374             : void
     375           0 : StructuredCloneData::CopyFromClonedMessageDataForBackgroundParent(const ClonedMessageData& aClonedData)
     376             : {
     377           0 :   MOZ_ASSERT(IsOnBackgroundThread());
     378           0 :   UnpackClonedMessageData<BorrowMemory, Parent>(aClonedData, *this);
     379           0 : }
     380             : 
     381             : void
     382           0 : StructuredCloneData::CopyFromClonedMessageDataForBackgroundChild(const ClonedMessageData& aClonedData)
     383             : {
     384           0 :   UnpackClonedMessageData<CopyMemory, Child>(aClonedData, *this);
     385           0 : }
     386             : 
     387             : void
     388           0 : StructuredCloneData::StealFromClonedMessageDataForParent(ClonedMessageData& aClonedData)
     389             : {
     390           0 :   MOZ_ASSERT(NS_IsMainThread());
     391           0 :   UnpackClonedMessageData<StealMemory, Parent>(aClonedData, *this);
     392           0 : }
     393             : 
     394             : void
     395           0 : StructuredCloneData::StealFromClonedMessageDataForChild(ClonedMessageData& aClonedData)
     396             : {
     397           0 :   MOZ_ASSERT(NS_IsMainThread());
     398           0 :   UnpackClonedMessageData<StealMemory, Child>(aClonedData, *this);
     399           0 : }
     400             : 
     401             : void
     402           0 : StructuredCloneData::StealFromClonedMessageDataForBackgroundParent(ClonedMessageData& aClonedData)
     403             : {
     404           0 :   MOZ_ASSERT(IsOnBackgroundThread());
     405           0 :   UnpackClonedMessageData<StealMemory, Parent>(aClonedData, *this);
     406           0 : }
     407             : 
     408             : void
     409           0 : StructuredCloneData::StealFromClonedMessageDataForBackgroundChild(ClonedMessageData& aClonedData)
     410             : {
     411           0 :   UnpackClonedMessageData<StealMemory, Child>(aClonedData, *this);
     412           0 : }
     413             : 
     414             : 
     415             : void
     416           2 : StructuredCloneData::WriteIPCParams(IPC::Message* aMsg) const
     417             : {
     418           2 :   WriteParam(aMsg, Data());
     419           2 : }
     420             : 
     421             : bool
     422           2 : StructuredCloneData::ReadIPCParams(const IPC::Message* aMsg,
     423             :                                    PickleIterator* aIter)
     424             : {
     425           2 :   MOZ_ASSERT(!mInitialized);
     426           4 :   JSStructuredCloneData data;
     427           2 :   if (!ReadParam(aMsg, aIter, &data)) {
     428           0 :     return false;
     429             :   }
     430           4 :   mSharedData = new SharedJSAllocatedData(Move(data));
     431           2 :   mInitialized = true;
     432           2 :   return true;
     433             : }
     434             : 
     435             : bool
     436           0 : StructuredCloneData::CopyExternalData(const char* aData,
     437             :                                       size_t aDataLength)
     438             : {
     439           0 :   MOZ_ASSERT(!mInitialized);
     440           0 :   mSharedData = SharedJSAllocatedData::CreateFromExternalData(aData,
     441           0 :                                                               aDataLength);
     442           0 :   NS_ENSURE_TRUE(mSharedData, false);
     443           0 :   mInitialized = true;
     444           0 :   return true;
     445             : }
     446             : 
     447             : bool
     448           0 : StructuredCloneData::CopyExternalData(const JSStructuredCloneData& aData)
     449             : {
     450           0 :   MOZ_ASSERT(!mInitialized);
     451           0 :   mSharedData = SharedJSAllocatedData::CreateFromExternalData(aData);
     452           0 :   NS_ENSURE_TRUE(mSharedData, false);
     453           0 :   mInitialized = true;
     454           0 :   return true;
     455             : }
     456             : 
     457             : bool
     458           0 : StructuredCloneData::StealExternalData(JSStructuredCloneData& aData)
     459             : {
     460           0 :   MOZ_ASSERT(!mInitialized);
     461           0 :   mSharedData = new SharedJSAllocatedData(Move(aData));
     462           0 :   mInitialized = true;
     463           0 :   return true;
     464             : }
     465             : 
     466             : } // namespace ipc
     467             : } // namespace dom
     468             : } // namespace mozilla

Generated by: LCOV version 1.13