Bug 1461426 - IPCBlobInputStreamParent should be sent as underlying stream to the content, r=smaug
authorAndrea Marchesini <amarchesini@mozilla.com>
Tue, 29 May 2018 20:02:03 +0200
changeset 801173 d7c3f83a905ef8d9d02cc6c02c752b285ae3165d
parent 801172 7e62b8b3202ad71a244567ff87b1a7a08c4fc9a2
child 801174 4ab1dbec331ee1d0826d1d586762c84842d5910b
push id111603
push usermozilla@kaply.com
push dateTue, 29 May 2018 22:12:07 +0000
reviewerssmaug
bugs1461426
milestone62.0a1
Bug 1461426 - IPCBlobInputStreamParent should be sent as underlying stream to the content, r=smaug
dom/file/ipc/IPCBlobInputStream.cpp
dom/file/ipc/IPCBlobInputStream.h
dom/file/ipc/IPCBlobUtils.cpp
--- a/dom/file/ipc/IPCBlobInputStream.cpp
+++ b/dom/file/ipc/IPCBlobInputStream.cpp
@@ -122,16 +122,17 @@ NS_INTERFACE_MAP_BEGIN(IPCBlobInputStrea
   NS_INTERFACE_MAP_ENTRY(nsIInputStreamCallback)
   NS_INTERFACE_MAP_ENTRY(nsICloneableInputStream)
   NS_INTERFACE_MAP_ENTRY(nsICloneableInputStreamWithRange)
   NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableInputStream)
   NS_INTERFACE_MAP_ENTRY(nsIFileMetadata)
   NS_INTERFACE_MAP_ENTRY(nsIAsyncFileMetadata)
   NS_INTERFACE_MAP_ENTRY(nsIInputStreamLength)
   NS_INTERFACE_MAP_ENTRY(nsIAsyncInputStreamLength)
+  NS_INTERFACE_MAP_ENTRY(nsIIPCBlobInputStream)
   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
 NS_INTERFACE_MAP_END
 
 IPCBlobInputStream::IPCBlobInputStream(IPCBlobInputStreamChild* aActor)
   : mActor(aActor)
   , mState(eInit)
   , mStart(0)
   , mLength(0)
--- a/dom/file/ipc/IPCBlobInputStream.h
+++ b/dom/file/ipc/IPCBlobInputStream.h
@@ -15,23 +15,40 @@
 #include "nsIInputStreamLength.h"
 #include "nsCOMPtr.h"
 
 namespace mozilla {
 namespace dom {
 
 class IPCBlobInputStreamChild;
 
+#define IPCBLOBINPUTSTREAM_IID \
+  { 0xbcfa38fc, 0x8b7f, 0x4d79, \
+    { 0xbe, 0x3a, 0x1e, 0x7b, 0xbe, 0x52, 0x38, 0xcd } }
+
+class nsIIPCBlobInputStream : public nsISupports
+{
+public:
+  NS_DECLARE_STATIC_IID_ACCESSOR(IPCBLOBINPUTSTREAM_IID)
+
+  virtual nsIInputStream*
+  GetInternalStream() const = 0;
+};
+
+NS_DEFINE_STATIC_IID_ACCESSOR(nsIIPCBlobInputStream,
+                              IPCBLOBINPUTSTREAM_IID)
+
 class IPCBlobInputStream final : public nsIAsyncInputStream
                                , public nsIInputStreamCallback
                                , public nsICloneableInputStreamWithRange
                                , public nsIIPCSerializableInputStream
                                , public nsIAsyncFileMetadata
                                , public nsIInputStreamLength
                                , public nsIAsyncInputStreamLength
+                               , public nsIIPCBlobInputStream
 {
 public:
   NS_DECL_THREADSAFE_ISUPPORTS
   NS_DECL_NSIINPUTSTREAM
   NS_DECL_NSIASYNCINPUTSTREAM
   NS_DECL_NSIINPUTSTREAMCALLBACK
   NS_DECL_NSICLONEABLEINPUTSTREAM
   NS_DECL_NSICLONEABLEINPUTSTREAMWITHRANGE
@@ -44,16 +61,31 @@ public:
   explicit IPCBlobInputStream(IPCBlobInputStreamChild* aActor);
 
   void
   StreamReady(already_AddRefed<nsIInputStream> aInputStream);
 
   void
   LengthReady(int64_t aLength);
 
+  // nsIIPCBlobInputStream
+  nsIInputStream*
+  GetInternalStream() const override
+  {
+    if (mRemoteStream) {
+     return mRemoteStream;
+    }
+
+    if (mAsyncRemoteStream) {
+      return mAsyncRemoteStream;
+    }
+
+    return nullptr;
+  }
+
 private:
   ~IPCBlobInputStream();
 
   nsresult
   EnsureAsyncRemoteStream(const MutexAutoLock& aProofOfLock);
 
   void
   InitWithExistingRange(uint64_t aStart, uint64_t aLength,
--- a/dom/file/ipc/IPCBlobUtils.cpp
+++ b/dom/file/ipc/IPCBlobUtils.cpp
@@ -84,20 +84,36 @@ Deserialize(const IPCBlob& aIPCBlob)
 template<typename M>
 nsresult
 SerializeInputStreamParent(nsIInputStream* aInputStream, uint64_t aSize,
                            uint64_t aChildID, IPCBlob& aIPCBlob, M* aManager)
 {
   // Parent to Child we always send a IPCBlobInputStream.
   MOZ_ASSERT(XRE_IsParentProcess());
 
+  nsCOMPtr<nsIInputStream> stream = aInputStream;
+
+  // In case this is a IPCBlobInputStream, we don't want to create a loop:
+  // IPCBlobInputStreamParent -> IPCBlobInputStream ->
+  // IPCBlobInputStreamParent. Let's use the underlying inputStream instead.
+  nsCOMPtr<nsIIPCBlobInputStream> ipcBlobInputStream =
+    do_QueryInterface(aInputStream);
+  if (ipcBlobInputStream) {
+    stream = ipcBlobInputStream->GetInternalStream();
+    // If we don't have an underlying stream, it's better to terminate here
+    // instead of sending an 'empty' IPCBlobInputStream actor on the other side,
+    // unable to be used.
+    if (NS_WARN_IF(!stream)) {
+      return NS_ERROR_FAILURE;
+    }
+  }
+
   nsresult rv;
   RefPtr<IPCBlobInputStreamParent> parentActor =
-    IPCBlobInputStreamParent::Create(aInputStream, aSize, aChildID, &rv,
-                                     aManager);
+    IPCBlobInputStreamParent::Create(stream, aSize, aChildID, &rv, aManager);
   if (!parentActor) {
     return rv;
   }
 
   // We need manually to increase the reference for this actor because the
   // IPC allocator method is not triggered. The Release() is called by IPDL
   // when the actor is deleted.
   parentActor.get()->AddRef();