Bug 1438026 - Part 1: Add IPDLParamTraits for RefPtr<BlobImpl>, r=baku
authorNika Layzell <nika@thelayzells.com>
Fri, 02 Mar 2018 13:13:48 -0500
changeset 412749 1c1e0d112e260b3213d81c429f25f99b34716eef
parent 412748 a6edd350b230916c11bcfbb5d68676b461bba28a
child 412750 7dadb3852649b5184bf5960b7565b0f15bee9b09
push id33818
push userapavel@mozilla.com
push dateWed, 11 Apr 2018 14:36:40 +0000
treeherdermozilla-central@cfe6399e142c [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbaku
bugs1438026
milestone61.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1438026 - Part 1: Add IPDLParamTraits for RefPtr<BlobImpl>, r=baku
dom/file/ipc/IPCBlobUtils.cpp
dom/file/ipc/IPCBlobUtils.h
--- a/dom/file/ipc/IPCBlobUtils.cpp
+++ b/dom/file/ipc/IPCBlobUtils.cpp
@@ -5,19 +5,23 @@
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #include "IPCBlobUtils.h"
 #include "IPCBlobInputStream.h"
 #include "IPCBlobInputStreamChild.h"
 #include "IPCBlobInputStreamParent.h"
 #include "IPCBlobInputStreamStorage.h"
 #include "mozilla/dom/IPCBlob.h"
-#include "mozilla/dom/nsIContentParent.h"
 #include "mozilla/ipc/BackgroundParent.h"
+#include "mozilla/ipc/PBackgroundParent.h"
+#include "mozilla/ipc/PBackgroundChild.h"
+#include "mozilla/dom/ContentParent.h"
+#include "mozilla/dom/ContentChild.h"
 #include "mozilla/ipc/IPCStreamUtils.h"
+#include "mozilla/ipc/ProtocolUtils.h"
 #include "StreamBlobImpl.h"
 #include "prtime.h"
 
 namespace mozilla {
 
 using namespace ipc;
 
 namespace dom {
@@ -254,11 +258,88 @@ Serialize(BlobImpl* aBlobImpl, nsIConten
 }
 
 nsresult
 Serialize(BlobImpl* aBlobImpl, PBackgroundParent* aManager, IPCBlob& aIPCBlob)
 {
   return SerializeInternal(aBlobImpl, aManager, aIPCBlob);
 }
 
+nsresult
+SerializeUntyped(BlobImpl* aBlobImpl, IProtocol* aActor, IPCBlob& aIPCBlob)
+{
+  // We always want to act on the toplevel protocol.
+  IProtocol* manager = aActor;
+  while (manager->Manager()) {
+    manager = manager->Manager();
+  }
+
+  // We always need the toplevel protocol
+  switch(manager->GetProtocolTypeId()) {
+  case PBackgroundMsgStart:
+    if (manager->GetSide() == mozilla::ipc::ParentSide) {
+      return SerializeInternal(aBlobImpl,
+                               static_cast<PBackgroundParent*>(manager),
+                               aIPCBlob);
+    } else {
+      return SerializeInternal(aBlobImpl,
+                               static_cast<PBackgroundChild*>(manager),
+                               aIPCBlob);
+    }
+  case PContentMsgStart:
+    if (manager->GetSide() == mozilla::ipc::ParentSide) {
+      return SerializeInternal(aBlobImpl,
+                               static_cast<ContentParent*>(manager),
+                               aIPCBlob);
+    } else {
+      return SerializeInternal(aBlobImpl,
+                               static_cast<ContentChild*>(manager),
+                               aIPCBlob);
+    }
+  default:
+    MOZ_CRASH("Unsupported protocol passed to BlobImpl serialize");
+  }
+}
+
 } // IPCBlobUtils namespace
 } // dom namespace
+
+namespace ipc {
+void
+IPDLParamTraits<RefPtr<mozilla::dom::BlobImpl>>::Write(
+  IPC::Message* aMsg, IProtocol* aActor,
+  const RefPtr<mozilla::dom::BlobImpl>& aParam)
+{
+  nsresult rv;
+  mozilla::dom::IPCBlob ipcblob;
+  if (aParam) {
+    rv = mozilla::dom::IPCBlobUtils::SerializeUntyped(aParam, aActor, ipcblob);
+  }
+  if (!aParam || NS_WARN_IF(NS_FAILED(rv))) {
+    WriteIPDLParam(aMsg, aActor, false);
+  } else {
+    WriteIPDLParam(aMsg, aActor, true);
+    WriteIPDLParam(aMsg, aActor, ipcblob);
+  }
+}
+
+bool
+IPDLParamTraits<RefPtr<mozilla::dom::BlobImpl>>::Read(
+  const IPC::Message* aMsg, PickleIterator* aIter,
+  IProtocol* aActor, RefPtr<mozilla::dom::BlobImpl>* aResult)
+{
+  *aResult = nullptr;
+
+  bool notnull = false;
+  if (!ReadIPDLParam(aMsg, aIter, aActor, &notnull)) {
+    return false;
+  }
+  if (notnull) {
+    mozilla::dom::IPCBlob ipcblob;
+    if (!ReadIPDLParam(aMsg, aIter, aActor, &ipcblob)) {
+      return false;
+    }
+    *aResult = mozilla::dom::IPCBlobUtils::Deserialize(ipcblob);
+  }
+  return true;
+}
+} // ipc namespace
 } // mozilla namespace
--- a/dom/file/ipc/IPCBlobUtils.h
+++ b/dom/file/ipc/IPCBlobUtils.h
@@ -2,17 +2,19 @@
 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
 /* This Source Code Form is subject to the terms of the Mozilla Public
  * License, v. 2.0. If a copy of the MPL was not distributed with this
  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
 
 #ifndef mozilla_dom_IPCBlobUtils_h
 #define mozilla_dom_IPCBlobUtils_h
 
+#include "mozilla/RefPtr.h"
 #include "mozilla/dom/File.h"
+#include "mozilla/ipc/IPDLParamTraits.h"
 
 /*
  * Blobs and IPC
  * ~~~~~~~~~~~~~
  *
  * Simplifying, DOM Blob objects are chunks of data with a content type and a
  * size. DOM Files are Blobs with a name. They are are used in many APIs and
  * they can be cloned and sent cross threads and cross processes.
@@ -207,28 +209,33 @@
  * When IPCBlobInputStream is serialized and sent to the parent process, start
  * and range are sent too and SlicedInputStream is used in the parent side as
  * well.
  */
 
 namespace mozilla {
 
 namespace ipc {
+class IProtocol;
 class PBackgroundChild;
 class PBackgroundParent;
 }
 
 namespace dom {
 
 class IPCBlob;
 class nsIContentChild;
 class nsIContentParent;
 
 namespace IPCBlobUtils {
 
+// Typedef for use within ipdl files, as the full type cannot be written
+// currently.
+typedef RefPtr<BlobImpl> BlobImplPtr;
+
 already_AddRefed<BlobImpl>
 Deserialize(const IPCBlob& aIPCBlob);
 
 // These 4 methods serialize aBlobImpl into aIPCBlob using the right manager.
 
 nsresult
 Serialize(BlobImpl* aBlobImpl, nsIContentChild* aManager, IPCBlob& aIPCBlob);
 
@@ -238,13 +245,33 @@ Serialize(BlobImpl* aBlobImpl, mozilla::
 
 nsresult
 Serialize(BlobImpl* aBlobImpl, nsIContentParent* aManager, IPCBlob& aIPCBlob);
 
 nsresult
 Serialize(BlobImpl* aBlobImpl, mozilla::ipc::PBackgroundParent* aManager,
           IPCBlob& aIPCBlob);
 
+// WARNING: If you pass any actor which does not have P{Content,Background} as
+// its toplevel protocol, this method will MOZ_CRASH.
+nsresult
+SerializeUntyped(BlobImpl* aBlobImpl, mozilla::ipc::IProtocol* aActor, IPCBlob& aIPCBlob);
+
 } // IPCBlobUtils
 } // dom namespace
+
+namespace ipc {
+// ParamTraits implementation for BlobImpl. N.B: If the original BlobImpl cannot
+// be successfully serialized, a warning will be produced and a nullptr will be
+// sent over the wire. When Read()-ing a BlobImpl,
+// __always make sure to handle null!__
+template<>
+struct IPDLParamTraits<RefPtr<mozilla::dom::BlobImpl>>
+{
+  static void Write(IPC::Message* aMsg, IProtocol* aActor,
+                    const RefPtr<mozilla::dom::BlobImpl>& aParam);
+  static bool Read(const IPC::Message* aMsg, PickleIterator* aIter,
+                   IProtocol* aActor, RefPtr<mozilla::dom::BlobImpl>* aResult);
+};
+} // ipc namespace
 } // mozilla namespace
 
 #endif // mozilla_dom_IPCBlobUtils_h